diff --git a/Example/AddContactForm.Designer.cs b/Example/AddContactForm.Designer.cs new file mode 100644 index 0000000..de731e6 --- /dev/null +++ b/Example/AddContactForm.Designer.cs @@ -0,0 +1,123 @@ +namespace MSNPSharpClient +{ + partial class AddContactForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.lblAccount = new System.Windows.Forms.Label(); + this.txtAccount = new System.Windows.Forms.TextBox(); + this.txtInvitation = new System.Windows.Forms.TextBox(); + this.lblInvitation = new System.Windows.Forms.Label(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // lblAccount + // + this.lblAccount.AutoSize = true; + this.lblAccount.Location = new System.Drawing.Point(4, 21); + this.lblAccount.Name = "lblAccount"; + this.lblAccount.Size = new System.Drawing.Size(106, 13); + this.lblAccount.TabIndex = 0; + this.lblAccount.Text = "Messenger address:*"; + // + // txtAccount + // + this.txtAccount.CharacterCasing = System.Windows.Forms.CharacterCasing.Lower; + this.txtAccount.Location = new System.Drawing.Point(115, 18); + this.txtAccount.Name = "txtAccount"; + this.txtAccount.Size = new System.Drawing.Size(250, 20); + this.txtAccount.TabIndex = 1; + // + // txtInvitation + // + this.txtInvitation.Location = new System.Drawing.Point(115, 47); + this.txtInvitation.Name = "txtInvitation"; + this.txtInvitation.Size = new System.Drawing.Size(250, 20); + this.txtInvitation.TabIndex = 2; + // + // lblInvitation + // + this.lblInvitation.AutoSize = true; + this.lblInvitation.Location = new System.Drawing.Point(12, 50); + this.lblInvitation.Name = "lblInvitation"; + this.lblInvitation.Size = new System.Drawing.Size(98, 13); + this.lblInvitation.TabIndex = 4; + this.lblInvitation.Text = "Invitation message:"; + // + // btnOK + // + this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; + this.btnOK.Location = new System.Drawing.Point(209, 84); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(75, 23); + this.btnOK.TabIndex = 3; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + this.btnOK.Click += new System.EventHandler(this.btn_Click); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(290, 84); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(75, 23); + this.btnCancel.TabIndex = 4; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + this.btnCancel.Click += new System.EventHandler(this.btn_Click); + // + // AddContactForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(373, 119); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.txtInvitation); + this.Controls.Add(this.lblInvitation); + this.Controls.Add(this.txtAccount); + this.Controls.Add(this.lblAccount); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "AddContactForm"; + this.Text = "Add New Contact"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label lblAccount; + private System.Windows.Forms.TextBox txtAccount; + private System.Windows.Forms.TextBox txtInvitation; + private System.Windows.Forms.Label lblInvitation; + private System.Windows.Forms.Button btnOK; + private System.Windows.Forms.Button btnCancel; + } +} \ No newline at end of file diff --git a/Example/AddContactForm.cs b/Example/AddContactForm.cs new file mode 100644 index 0000000..d0a3634 --- /dev/null +++ b/Example/AddContactForm.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +namespace MSNPSharpClient +{ + public partial class AddContactForm : Form + { + public AddContactForm(string account) + { + InitializeComponent(); + + if (!String.IsNullOrEmpty(account)) + { + this.account = account; + txtAccount.Text = account; + } + } + + private string account; + public string Account + { + get + { + return account; + } + } + + private string invitationMessage; + public string InvitationMessage + { + get + { + return invitationMessage; + } + } + + private void btn_Click(object sender, EventArgs e) + { + account = txtAccount.Text; + invitationMessage = txtInvitation.Text; + + Close(); + } + } +} \ No newline at end of file diff --git a/Example/AddContactForm.resx b/Example/AddContactForm.resx new file mode 100644 index 0000000..19dc0dd --- /dev/null +++ b/Example/AddContactForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Example/ContactCardForm.Designer.cs b/Example/ContactCardForm.Designer.cs new file mode 100644 index 0000000..ca17b2e --- /dev/null +++ b/Example/ContactCardForm.Designer.cs @@ -0,0 +1,240 @@ +namespace MSNPSharpClient +{ + partial class ContactCardForm + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows 窗体设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.pnlSpace = new System.Windows.Forms.Panel(); + this.panel3 = new System.Windows.Forms.Panel(); + this.lblSpaceTitle = new System.Windows.Forms.LinkLabel(); + this.lblDisplayName = new System.Windows.Forms.Label(); + this.picDisplayImage = new System.Windows.Forms.PictureBox(); + this.pnlAlbum = new System.Windows.Forms.Panel(); + this.tlpnlAlbum = new System.Windows.Forms.TableLayoutPanel(); + this.lnkAlbumName = new System.Windows.Forms.LinkLabel(); + this.pnlBlog = new System.Windows.Forms.Panel(); + this.lnkBlogContent = new System.Windows.Forms.LinkLabel(); + this.lnkBlogTitle = new System.Windows.Forms.LinkLabel(); + this.pnlProfile = new System.Windows.Forms.Panel(); + this.ttips = new System.Windows.Forms.ToolTip(this.components); + this.pnlSpace.SuspendLayout(); + this.panel3.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.picDisplayImage)).BeginInit(); + this.pnlAlbum.SuspendLayout(); + this.pnlBlog.SuspendLayout(); + this.SuspendLayout(); + // + // pnlSpace + // + this.pnlSpace.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(128)))), ((int)(((byte)(255))))); + this.pnlSpace.Controls.Add(this.panel3); + this.pnlSpace.Controls.Add(this.picDisplayImage); + this.pnlSpace.Dock = System.Windows.Forms.DockStyle.Top; + this.pnlSpace.Location = new System.Drawing.Point(0, 0); + this.pnlSpace.Name = "pnlSpace"; + this.pnlSpace.Padding = new System.Windows.Forms.Padding(10); + this.pnlSpace.Size = new System.Drawing.Size(272, 76); + this.pnlSpace.TabIndex = 1; + // + // panel3 + // + this.panel3.Controls.Add(this.lblSpaceTitle); + this.panel3.Controls.Add(this.lblDisplayName); + this.panel3.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel3.Location = new System.Drawing.Point(69, 10); + this.panel3.Name = "panel3"; + this.panel3.Size = new System.Drawing.Size(193, 56); + this.panel3.TabIndex = 2; + // + // lblSpaceTitle + // + this.lblSpaceTitle.Dock = System.Windows.Forms.DockStyle.Top; + this.lblSpaceTitle.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline; + this.lblSpaceTitle.Location = new System.Drawing.Point(0, 23); + this.lblSpaceTitle.Margin = new System.Windows.Forms.Padding(0); + this.lblSpaceTitle.Name = "lblSpaceTitle"; + this.lblSpaceTitle.Padding = new System.Windows.Forms.Padding(10, 0, 0, 0); + this.lblSpaceTitle.Size = new System.Drawing.Size(193, 19); + this.lblSpaceTitle.TabIndex = 2; + this.lblSpaceTitle.TabStop = true; + this.lblSpaceTitle.Text = "Space Title"; + this.lblSpaceTitle.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.lblSpaceTitle_LinkClicked); + // + // lblDisplayName + // + this.lblDisplayName.Dock = System.Windows.Forms.DockStyle.Top; + this.lblDisplayName.Location = new System.Drawing.Point(0, 0); + this.lblDisplayName.Margin = new System.Windows.Forms.Padding(0); + this.lblDisplayName.Name = "lblDisplayName"; + this.lblDisplayName.Padding = new System.Windows.Forms.Padding(10, 0, 0, 0); + this.lblDisplayName.Size = new System.Drawing.Size(193, 23); + this.lblDisplayName.TabIndex = 1; + this.lblDisplayName.Text = "Display Name"; + // + // picDisplayImage + // + this.picDisplayImage.BackColor = System.Drawing.Color.White; + this.picDisplayImage.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.picDisplayImage.Dock = System.Windows.Forms.DockStyle.Left; + this.picDisplayImage.Location = new System.Drawing.Point(10, 10); + this.picDisplayImage.Name = "picDisplayImage"; + this.picDisplayImage.Size = new System.Drawing.Size(59, 56); + this.picDisplayImage.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.picDisplayImage.TabIndex = 1; + this.picDisplayImage.TabStop = false; + // + // pnlAlbum + // + this.pnlAlbum.BackColor = System.Drawing.Color.Linen; + this.pnlAlbum.Controls.Add(this.tlpnlAlbum); + this.pnlAlbum.Controls.Add(this.lnkAlbumName); + this.pnlAlbum.Dock = System.Windows.Forms.DockStyle.Top; + this.pnlAlbum.Location = new System.Drawing.Point(0, 76); + this.pnlAlbum.Name = "pnlAlbum"; + this.pnlAlbum.Padding = new System.Windows.Forms.Padding(5); + this.pnlAlbum.Size = new System.Drawing.Size(272, 65); + this.pnlAlbum.TabIndex = 2; + // + // tlpnlAlbum + // + this.tlpnlAlbum.ColumnCount = 6; + this.tlpnlAlbum.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tlpnlAlbum.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tlpnlAlbum.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tlpnlAlbum.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tlpnlAlbum.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tlpnlAlbum.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tlpnlAlbum.Dock = System.Windows.Forms.DockStyle.Fill; + this.tlpnlAlbum.Location = new System.Drawing.Point(5, 17); + this.tlpnlAlbum.Name = "tlpnlAlbum"; + this.tlpnlAlbum.RowCount = 1; + this.tlpnlAlbum.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tlpnlAlbum.Size = new System.Drawing.Size(262, 43); + this.tlpnlAlbum.TabIndex = 1; + // + // lnkAlbumName + // + this.lnkAlbumName.Dock = System.Windows.Forms.DockStyle.Top; + this.lnkAlbumName.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline; + this.lnkAlbumName.Location = new System.Drawing.Point(5, 5); + this.lnkAlbumName.Name = "lnkAlbumName"; + this.lnkAlbumName.Size = new System.Drawing.Size(262, 12); + this.lnkAlbumName.TabIndex = 0; + this.lnkAlbumName.TabStop = true; + this.lnkAlbumName.Text = "Album Name"; + this.lnkAlbumName.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.lnkAlbumName_LinkClicked); + // + // pnlBlog + // + this.pnlBlog.BackColor = System.Drawing.Color.Linen; + this.pnlBlog.Controls.Add(this.lnkBlogContent); + this.pnlBlog.Controls.Add(this.lnkBlogTitle); + this.pnlBlog.Dock = System.Windows.Forms.DockStyle.Top; + this.pnlBlog.Location = new System.Drawing.Point(0, 141); + this.pnlBlog.Name = "pnlBlog"; + this.pnlBlog.Padding = new System.Windows.Forms.Padding(5); + this.pnlBlog.Size = new System.Drawing.Size(272, 58); + this.pnlBlog.TabIndex = 3; + // + // lnkBlogContent + // + this.lnkBlogContent.Dock = System.Windows.Forms.DockStyle.Fill; + this.lnkBlogContent.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline; + this.lnkBlogContent.Location = new System.Drawing.Point(5, 17); + this.lnkBlogContent.Name = "lnkBlogContent"; + this.lnkBlogContent.Size = new System.Drawing.Size(262, 36); + this.lnkBlogContent.TabIndex = 1; + this.lnkBlogContent.TabStop = true; + this.lnkBlogContent.Text = "Blog Content"; + this.lnkBlogContent.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.lnkBlogContent_LinkClicked); + // + // lnkBlogTitle + // + this.lnkBlogTitle.Dock = System.Windows.Forms.DockStyle.Top; + this.lnkBlogTitle.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline; + this.lnkBlogTitle.LinkColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64))))); + this.lnkBlogTitle.Location = new System.Drawing.Point(5, 5); + this.lnkBlogTitle.Name = "lnkBlogTitle"; + this.lnkBlogTitle.Size = new System.Drawing.Size(262, 12); + this.lnkBlogTitle.TabIndex = 0; + this.lnkBlogTitle.TabStop = true; + this.lnkBlogTitle.Text = "Blog Title"; + this.lnkBlogTitle.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.lnkBlogTitle_LinkClicked); + // + // pnlProfile + // + this.pnlProfile.BackColor = System.Drawing.Color.Linen; + this.pnlProfile.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlProfile.Location = new System.Drawing.Point(0, 199); + this.pnlProfile.Name = "pnlProfile"; + this.pnlProfile.Padding = new System.Windows.Forms.Padding(5); + this.pnlProfile.Size = new System.Drawing.Size(272, 35); + this.pnlProfile.TabIndex = 4; + // + // ContactCardForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(272, 234); + this.Controls.Add(this.pnlProfile); + this.Controls.Add(this.pnlBlog); + this.Controls.Add(this.pnlAlbum); + this.Controls.Add(this.pnlSpace); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.Name = "ContactCardForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "ContactCard"; + this.Load += new System.EventHandler(this.ContactCardForm_Load); + this.pnlSpace.ResumeLayout(false); + this.panel3.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.picDisplayImage)).EndInit(); + this.pnlAlbum.ResumeLayout(false); + this.pnlBlog.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Panel pnlSpace; + private System.Windows.Forms.Panel panel3; + private System.Windows.Forms.LinkLabel lblSpaceTitle; + private System.Windows.Forms.Label lblDisplayName; + private System.Windows.Forms.PictureBox picDisplayImage; + private System.Windows.Forms.Panel pnlAlbum; + private System.Windows.Forms.TableLayoutPanel tlpnlAlbum; + private System.Windows.Forms.LinkLabel lnkAlbumName; + private System.Windows.Forms.Panel pnlBlog; + private System.Windows.Forms.Panel pnlProfile; + private System.Windows.Forms.LinkLabel lnkBlogContent; + private System.Windows.Forms.LinkLabel lnkBlogTitle; + private System.Windows.Forms.ToolTip ttips; + + } +} \ No newline at end of file diff --git a/Example/ContactCardForm.cs b/Example/ContactCardForm.cs new file mode 100644 index 0000000..6521a72 --- /dev/null +++ b/Example/ContactCardForm.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using MSNPSharp; +using System.Diagnostics; + +namespace MSNPSharpClient +{ + public partial class ContactCardForm : Form + { + private ContactCard card = null; + + public ContactCardForm(ContactCard cc) + { + InitializeComponent(); + card = cc; + } + + private void ContactCardForm_Load(object sender, EventArgs e) + { + lblDisplayName.Text = card.DisplayName; + lblSpaceTitle.Text = (card.Space != null) ? card.Space.Title : String.Empty; + + if (String.IsNullOrEmpty(card.DisplayImageUrl)) + { + picDisplayImage.Visible = false; + } + else + { + picDisplayImage.LoadAsync(card.DisplayImageUrl); + } + + if (card.Album != null) + { + lnkAlbumName.Text = card.Album.Title; + int col = 0; + foreach (ThumbnailImage img in card.Album.Photos) //Setting the thumbnail pictures. + { + PictureBox lnkPic = new PictureBox(); + lnkPic.Dock = DockStyle.Fill; + lnkPic.Margin = new Padding(6); + lnkPic.BorderStyle = BorderStyle.FixedSingle; + lnkPic.SizeMode = PictureBoxSizeMode.Zoom; + lnkPic.BackColor = Color.White; + lnkPic.LoadAsync(img.ThumbnailUrl); + + tlpnlAlbum.Controls.Add(lnkPic, col, 0); + lnkPic.Tag = col; + lnkPic.Visible = true; + lnkPic.Click += new EventHandler(lnkPic_Click); + ttips.SetToolTip(lnkPic, img.ToolTip); + col++; + } + } + else + { + pnlAlbum.Visible = false; + } + + if (card.NewPost != null) + { + lnkBlogTitle.Text = card.NewPost.Title; + ttips.SetToolTip(lnkBlogTitle, card.NewPost.Description); + lnkBlogContent.Text = card.NewPost.Description; + ttips.SetToolTip(lnkBlogContent, card.NewPost.Description); + } + else + { + pnlBlog.Visible = false; + } + + Text = card.DisplayName + "'s ContactCard"; + } + + void lnkPic_Click(object sender, EventArgs e) + { + Process.Start(card.Album.Photos[(int)((PictureBox)sender).Tag].Url); + } + + void lnkPic_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Process.Start(card.Album.Photos[(int)((LinkLabel)sender).Tag].Url); + } + + private void lblSpaceTitle_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Process.Start(card.Space.Url); + } + + private void lnkAlbumName_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Process.Start(card.Album.Url); + } + + private void lnkBlogTitle_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Process.Start(card.NewPost.Url); + } + + private void lnkBlogContent_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Process.Start(card.NewPost.Url); + } + } +} \ No newline at end of file diff --git a/Example/ContactCardForm.resx b/Example/ContactCardForm.resx new file mode 100644 index 0000000..1d5cd69 --- /dev/null +++ b/Example/ContactCardForm.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/Example/ConversationForm.cs b/Example/ConversationForm.cs new file mode 100644 index 0000000..042b525 --- /dev/null +++ b/Example/ConversationForm.cs @@ -0,0 +1,1077 @@ +using System; +using System.IO; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Collections; +using System.Windows.Forms; +using System.ComponentModel; +using System.Drawing.Imaging; +using System.Collections.Generic; +using System.Diagnostics; +using System.Threading; + +namespace MSNPSharpClient +{ + using MSNPSharp; + using MSNPSharp.DataTransfer; + using MSNPSharp.Core; + using MSNPSharp.Utilities; + + /// + /// Summary description for ConversationForm. + /// + public class ConversationForm : System.Windows.Forms.Form + { + private IContainer components; + #region Windows Form Designer generated code + + private Panel panel1; + private TextBox inputTextBox; + private Panel panel2; + private RtfRichTextBox richTextHistory; + private PictureBox displayOwner; + private PictureBox displayUser; + + private OpenFileDialog openFileDialog; + private ToolStrip tsMessage; + private ToolStripComboBox cbMessageFontName; + private ToolStripComboBox cbMessageFontSize; + private ToolStripSeparator tssMessageSeperator1; + private ToolStripButton bMessageBold; + private ToolStripButton bMessageItalic; + private ToolStripButton bMessageUnderline; + private ToolStripSeparator tssMessageSeperator2; + private ToolStripButton bMessageSend; + private ToolStripButton bMessageSendNudge; + private Button btnSendFiles; + private Button btnInviteUsers; + private Button btnCustomEmoticon; + private Button btnActivityTest; + private ToolStripDropDownButton bMessageInsertEmoticon; + private ToolStripMenuItem toolStripMenuItem1; + private ToolStripMenuItem bigRinToolStripMenuItem; + private ToolStripMenuItem sadToolStripMenuItem; + private ToolStripMenuItem winkToolStripMenuItem; + private ToolStripMenuItem tongueOutToolStripMenuItem; + private ContextMenuStrip onlineUsersDropDown; + private ToolStripButton bMessageFontColor; + private OpenFileDialog openCustomEmoticonDialog; + private ColorDialog dlgColor; + + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.panel1 = new System.Windows.Forms.Panel(); + this.tsMessage = new System.Windows.Forms.ToolStrip(); + this.bMessageInsertEmoticon = new System.Windows.Forms.ToolStripDropDownButton(); + this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.bigRinToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.sadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.winkToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.tongueOutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.bMessageSendNudge = new System.Windows.Forms.ToolStripButton(); + this.tssMessageSeperator1 = new System.Windows.Forms.ToolStripSeparator(); + this.bMessageFontColor = new System.Windows.Forms.ToolStripButton(); + this.bMessageBold = new System.Windows.Forms.ToolStripButton(); + this.bMessageItalic = new System.Windows.Forms.ToolStripButton(); + this.bMessageUnderline = new System.Windows.Forms.ToolStripButton(); + this.cbMessageFontName = new System.Windows.Forms.ToolStripComboBox(); + this.cbMessageFontSize = new System.Windows.Forms.ToolStripComboBox(); + this.tssMessageSeperator2 = new System.Windows.Forms.ToolStripSeparator(); + this.bMessageSend = new System.Windows.Forms.ToolStripButton(); + this.displayOwner = new System.Windows.Forms.PictureBox(); + this.inputTextBox = new System.Windows.Forms.TextBox(); + this.panel2 = new System.Windows.Forms.Panel(); + this.btnActivityTest = new System.Windows.Forms.Button(); + this.btnCustomEmoticon = new System.Windows.Forms.Button(); + this.btnInviteUsers = new System.Windows.Forms.Button(); + this.onlineUsersDropDown = new System.Windows.Forms.ContextMenuStrip(this.components); + this.btnSendFiles = new System.Windows.Forms.Button(); + this.displayUser = new System.Windows.Forms.PictureBox(); + this.richTextHistory = new MSNPSharpClient.RtfRichTextBox(); + this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); + this.dlgColor = new System.Windows.Forms.ColorDialog(); + this.openCustomEmoticonDialog = new System.Windows.Forms.OpenFileDialog(); + this.panel1.SuspendLayout(); + this.tsMessage.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.displayOwner)).BeginInit(); + this.panel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.displayUser)).BeginInit(); + this.SuspendLayout(); + // + // panel1 + // + this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(163)))), ((int)(((byte)(163)))), ((int)(((byte)(186))))); + this.panel1.Controls.Add(this.tsMessage); + this.panel1.Controls.Add(this.displayOwner); + this.panel1.Controls.Add(this.inputTextBox); + this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom; + this.panel1.Location = new System.Drawing.Point(0, 272); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(663, 111); + this.panel1.TabIndex = 0; + // + // tsMessage + // + this.tsMessage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tsMessage.AutoSize = false; + this.tsMessage.Dock = System.Windows.Forms.DockStyle.None; + this.tsMessage.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsMessage.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.bMessageInsertEmoticon, + this.bMessageSendNudge, + this.tssMessageSeperator1, + this.bMessageFontColor, + this.bMessageBold, + this.bMessageItalic, + this.bMessageUnderline, + this.cbMessageFontName, + this.cbMessageFontSize, + this.tssMessageSeperator2, + this.bMessageSend}); + this.tsMessage.Location = new System.Drawing.Point(109, 3); + this.tsMessage.Name = "tsMessage"; + this.tsMessage.Padding = new System.Windows.Forms.Padding(3, 0, 1, 0); + this.tsMessage.Size = new System.Drawing.Size(550, 25); + this.tsMessage.TabIndex = 8; + // + // bMessageInsertEmoticon + // + this.bMessageInsertEmoticon.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.bMessageInsertEmoticon.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripMenuItem1, + this.bigRinToolStripMenuItem, + this.sadToolStripMenuItem, + this.winkToolStripMenuItem, + this.tongueOutToolStripMenuItem}); + this.bMessageInsertEmoticon.Image = global::MSNPSharpClient.Properties.Resources.smiley; + this.bMessageInsertEmoticon.ImageTransparentColor = System.Drawing.Color.Magenta; + this.bMessageInsertEmoticon.Name = "bMessageInsertEmoticon"; + this.bMessageInsertEmoticon.Size = new System.Drawing.Size(29, 22); + this.bMessageInsertEmoticon.Text = "toolStripDropDownButton1"; + // + // toolStripMenuItem1 + // + this.toolStripMenuItem1.Image = global::MSNPSharpClient.Properties.Resources.smiley; + this.toolStripMenuItem1.Name = "toolStripMenuItem1"; + this.toolStripMenuItem1.Size = new System.Drawing.Size(138, 22); + this.toolStripMenuItem1.Text = "Simley"; + this.toolStripMenuItem1.ToolTipText = ":)"; + this.toolStripMenuItem1.Click += new System.EventHandler(this.emotionDropDown_Click); + // + // bigRinToolStripMenuItem + // + this.bigRinToolStripMenuItem.Image = global::MSNPSharpClient.Properties.Resources.biggrin; + this.bigRinToolStripMenuItem.Name = "bigRinToolStripMenuItem"; + this.bigRinToolStripMenuItem.Size = new System.Drawing.Size(138, 22); + this.bigRinToolStripMenuItem.Text = "Big Grin"; + this.bigRinToolStripMenuItem.ToolTipText = ":d"; + this.bigRinToolStripMenuItem.Click += new System.EventHandler(this.emotionDropDown_Click); + // + // sadToolStripMenuItem + // + this.sadToolStripMenuItem.Image = global::MSNPSharpClient.Properties.Resources.sad; + this.sadToolStripMenuItem.Name = "sadToolStripMenuItem"; + this.sadToolStripMenuItem.Size = new System.Drawing.Size(138, 22); + this.sadToolStripMenuItem.Text = "Sad"; + this.sadToolStripMenuItem.ToolTipText = ":("; + this.sadToolStripMenuItem.Click += new System.EventHandler(this.emotionDropDown_Click); + // + // winkToolStripMenuItem + // + this.winkToolStripMenuItem.Image = global::MSNPSharpClient.Properties.Resources.wink; + this.winkToolStripMenuItem.Name = "winkToolStripMenuItem"; + this.winkToolStripMenuItem.Size = new System.Drawing.Size(138, 22); + this.winkToolStripMenuItem.Text = "Wink"; + this.winkToolStripMenuItem.ToolTipText = ";)"; + this.winkToolStripMenuItem.Click += new System.EventHandler(this.emotionDropDown_Click); + // + // tongueOutToolStripMenuItem + // + this.tongueOutToolStripMenuItem.Image = global::MSNPSharpClient.Properties.Resources.tongueout; + this.tongueOutToolStripMenuItem.Name = "tongueOutToolStripMenuItem"; + this.tongueOutToolStripMenuItem.Size = new System.Drawing.Size(138, 22); + this.tongueOutToolStripMenuItem.Text = "Tongue Out"; + this.tongueOutToolStripMenuItem.ToolTipText = ":p"; + this.tongueOutToolStripMenuItem.Click += new System.EventHandler(this.emotionDropDown_Click); + // + // bMessageSendNudge + // + this.bMessageSendNudge.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.bMessageSendNudge.Image = global::MSNPSharpClient.Properties.Resources.nudge; + this.bMessageSendNudge.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; + this.bMessageSendNudge.ImageTransparentColor = System.Drawing.Color.Magenta; + this.bMessageSendNudge.Name = "bMessageSendNudge"; + this.bMessageSendNudge.Size = new System.Drawing.Size(28, 22); + this.bMessageSendNudge.Text = "Send a &nudge"; + this.bMessageSendNudge.Click += new System.EventHandler(this.bMessageSendNudge_Click); + // + // tssMessageSeperator1 + // + this.tssMessageSeperator1.Name = "tssMessageSeperator1"; + this.tssMessageSeperator1.Size = new System.Drawing.Size(6, 25); + // + // bMessageFontColor + // + this.bMessageFontColor.Image = global::MSNPSharpClient.Properties.Resources.Color_fontHS; + this.bMessageFontColor.ImageTransparentColor = System.Drawing.Color.Magenta; + this.bMessageFontColor.Name = "bMessageFontColor"; + this.bMessageFontColor.Size = new System.Drawing.Size(56, 22); + this.bMessageFontColor.Text = "Color"; + this.bMessageFontColor.Click += new System.EventHandler(this.bMessageFontColor_Click); + // + // bMessageBold + // + this.bMessageBold.CheckOnClick = true; + this.bMessageBold.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.bMessageBold.Font = new System.Drawing.Font("Times New Roman", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.bMessageBold.ImageTransparentColor = System.Drawing.Color.Magenta; + this.bMessageBold.Name = "bMessageBold"; + this.bMessageBold.Size = new System.Drawing.Size(23, 22); + this.bMessageBold.Text = "B"; + this.bMessageBold.ToolTipText = "Bold"; + this.bMessageBold.CheckedChanged += new System.EventHandler(this.bMessageBoldItalicUnderline_CheckedChanged); + // + // bMessageItalic + // + this.bMessageItalic.CheckOnClick = true; + this.bMessageItalic.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.bMessageItalic.Font = new System.Drawing.Font("Times New Roman", 9.75F, System.Drawing.FontStyle.Italic, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.bMessageItalic.ImageTransparentColor = System.Drawing.Color.Magenta; + this.bMessageItalic.Name = "bMessageItalic"; + this.bMessageItalic.Size = new System.Drawing.Size(23, 22); + this.bMessageItalic.Text = "I"; + this.bMessageItalic.ToolTipText = "Italic"; + this.bMessageItalic.CheckedChanged += new System.EventHandler(this.bMessageBoldItalicUnderline_CheckedChanged); + // + // bMessageUnderline + // + this.bMessageUnderline.CheckOnClick = true; + this.bMessageUnderline.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.bMessageUnderline.Font = new System.Drawing.Font("Times New Roman", 9.75F, System.Drawing.FontStyle.Underline, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.bMessageUnderline.ImageTransparentColor = System.Drawing.Color.Magenta; + this.bMessageUnderline.Name = "bMessageUnderline"; + this.bMessageUnderline.Size = new System.Drawing.Size(23, 22); + this.bMessageUnderline.Text = "U"; + this.bMessageUnderline.ToolTipText = "Underline"; + this.bMessageUnderline.CheckedChanged += new System.EventHandler(this.bMessageBoldItalicUnderline_CheckedChanged); + // + // cbMessageFontName + // + this.cbMessageFontName.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend; + this.cbMessageFontName.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems; + this.cbMessageFontName.DropDownWidth = 200; + this.cbMessageFontName.MaxDropDownItems = 12; + this.cbMessageFontName.Name = "cbMessageFontName"; + this.cbMessageFontName.Size = new System.Drawing.Size(140, 25); + this.cbMessageFontName.ToolTipText = "Font Name"; + this.cbMessageFontName.SelectedIndexChanged += new System.EventHandler(this.cbMessageFontName_SelectedIndexChanged); + this.cbMessageFontName.Validating += new System.ComponentModel.CancelEventHandler(this.cbMessageFontName_Validating); + this.cbMessageFontName.Validated += new System.EventHandler(this.cbMessageFontName_Validated); + // + // cbMessageFontSize + // + this.cbMessageFontSize.Items.AddRange(new object[] { + "8", + "9", + "10", + "11", + "12", + "14", + "16", + "18", + "20", + "22", + "24", + "26", + "28", + "36", + "48", + "72"}); + this.cbMessageFontSize.MaxDropDownItems = 12; + this.cbMessageFontSize.Name = "cbMessageFontSize"; + this.cbMessageFontSize.Size = new System.Drawing.Size(75, 25); + this.cbMessageFontSize.ToolTipText = "Font Size"; + this.cbMessageFontSize.SelectedIndexChanged += new System.EventHandler(this.cbMessageFontSize_SelectedIndexChanged); + this.cbMessageFontSize.Validating += new System.ComponentModel.CancelEventHandler(this.cbMessageFontSize_Validating); + this.cbMessageFontSize.Validated += new System.EventHandler(this.cbMessageFontSize_Validated); + // + // tssMessageSeperator2 + // + this.tssMessageSeperator2.Name = "tssMessageSeperator2"; + this.tssMessageSeperator2.Size = new System.Drawing.Size(6, 25); + // + // bMessageSend + // + this.bMessageSend.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right; + this.bMessageSend.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.bMessageSend.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold); + this.bMessageSend.ImageTransparentColor = System.Drawing.Color.Magenta; + this.bMessageSend.Name = "bMessageSend"; + this.bMessageSend.Overflow = System.Windows.Forms.ToolStripItemOverflow.Never; + this.bMessageSend.Size = new System.Drawing.Size(57, 22); + this.bMessageSend.Text = " &Send "; + this.bMessageSend.Click += new System.EventHandler(this.bMessageSend_Click); + // + // displayOwner + // + this.displayOwner.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.displayOwner.BackColor = System.Drawing.Color.White; + this.displayOwner.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.displayOwner.Location = new System.Drawing.Point(3, 3); + this.displayOwner.Name = "displayOwner"; + this.displayOwner.Size = new System.Drawing.Size(100, 100); + this.displayOwner.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.displayOwner.TabIndex = 0; + this.displayOwner.TabStop = false; + // + // inputTextBox + // + this.inputTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.inputTextBox.Location = new System.Drawing.Point(109, 31); + this.inputTextBox.Multiline = true; + this.inputTextBox.Name = "inputTextBox"; + this.inputTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.inputTextBox.Size = new System.Drawing.Size(550, 72); + this.inputTextBox.TabIndex = 1; + this.inputTextBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.inputTextBox_KeyDown); + this.inputTextBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.inputTextBox_KeyPress); + // + // panel2 + // + this.panel2.Controls.Add(this.btnActivityTest); + this.panel2.Controls.Add(this.btnCustomEmoticon); + this.panel2.Controls.Add(this.btnInviteUsers); + this.panel2.Controls.Add(this.btnSendFiles); + this.panel2.Controls.Add(this.displayUser); + this.panel2.Controls.Add(this.richTextHistory); + this.panel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel2.Location = new System.Drawing.Point(0, 0); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(663, 272); + this.panel2.TabIndex = 0; + // + // btnActivityTest + // + this.btnActivityTest.Location = new System.Drawing.Point(3, 98); + this.btnActivityTest.Name = "btnActivityTest"; + this.btnActivityTest.Size = new System.Drawing.Size(100, 24); + this.btnActivityTest.TabIndex = 4; + this.btnActivityTest.Text = "Activity Test"; + this.btnActivityTest.UseVisualStyleBackColor = true; + this.btnActivityTest.Click += new System.EventHandler(this.btnActivityTest_Click); + // + // btnCustomEmoticon + // + this.btnCustomEmoticon.Location = new System.Drawing.Point(3, 41); + this.btnCustomEmoticon.Name = "btnCustomEmoticon"; + this.btnCustomEmoticon.Size = new System.Drawing.Size(100, 23); + this.btnCustomEmoticon.TabIndex = 3; + this.btnCustomEmoticon.Text = "Custom Emoticon"; + this.btnCustomEmoticon.UseVisualStyleBackColor = true; + this.btnCustomEmoticon.Click += new System.EventHandler(this.bMessageSendCustomEmoticon_Click); + // + // btnInviteUsers + // + this.btnInviteUsers.ContextMenuStrip = this.onlineUsersDropDown; + this.btnInviteUsers.Location = new System.Drawing.Point(3, 70); + this.btnInviteUsers.Name = "btnInviteUsers"; + this.btnInviteUsers.Size = new System.Drawing.Size(100, 23); + this.btnInviteUsers.TabIndex = 2; + this.btnInviteUsers.Text = "Invite Users"; + this.btnInviteUsers.UseVisualStyleBackColor = true; + this.btnInviteUsers.Click += new System.EventHandler(this.btnInviteUsers_Click); + // + // onlineUsersDropDown + // + this.onlineUsersDropDown.Name = "onlineUsersDropDown"; + this.onlineUsersDropDown.Size = new System.Drawing.Size(61, 4); + // + // btnSendFiles + // + this.btnSendFiles.Location = new System.Drawing.Point(3, 12); + this.btnSendFiles.Name = "btnSendFiles"; + this.btnSendFiles.Size = new System.Drawing.Size(100, 23); + this.btnSendFiles.TabIndex = 1; + this.btnSendFiles.Text = "Send Files"; + this.btnSendFiles.UseVisualStyleBackColor = true; + this.btnSendFiles.Click += new System.EventHandler(this.bMessageSendFiles_Click); + // + // displayUser + // + this.displayUser.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.displayUser.BackColor = System.Drawing.Color.White; + this.displayUser.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.displayUser.Location = new System.Drawing.Point(3, 166); + this.displayUser.Name = "displayUser"; + this.displayUser.Size = new System.Drawing.Size(100, 101); + this.displayUser.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.displayUser.TabIndex = 0; + this.displayUser.TabStop = false; + // + // richTextHistory + // + this.richTextHistory.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.richTextHistory.BackColor = System.Drawing.Color.Snow; + this.richTextHistory.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.richTextHistory.HiglightColor = MSNPSharpClient.RtfRichTextBox.RtfColor.White; + this.richTextHistory.Location = new System.Drawing.Point(109, 3); + this.richTextHistory.Name = "richTextHistory"; + this.richTextHistory.ReadOnly = true; + this.richTextHistory.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical; + this.richTextHistory.Size = new System.Drawing.Size(554, 264); + this.richTextHistory.TabIndex = 0; + this.richTextHistory.TabStop = false; + this.richTextHistory.Text = ""; + this.richTextHistory.TextColor = MSNPSharpClient.RtfRichTextBox.RtfColor.Black; + // + // openFileDialog + // + this.openFileDialog.Multiselect = true; + // + // openCustomEmoticonDialog + // + this.openCustomEmoticonDialog.Filter = "Image File (*.png, *.jpg, *.bmp, *.gif|*.png;*.jpg;*.bmp;*.gif"; + this.openCustomEmoticonDialog.Title = "Open Image to transfer as an custom emoticon"; + // + // ConversationForm + // + this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); + this.ClientSize = new System.Drawing.Size(663, 383); + this.Controls.Add(this.panel2); + this.Controls.Add(this.panel1); + this.Name = "ConversationForm"; + this.Text = "Conversation - MSNPSharp"; + this.Load += new System.EventHandler(this.ConversationForm_Load); + this.Shown += new System.EventHandler(this.ConversationForm_Shown); + this.Closing += new System.ComponentModel.CancelEventHandler(this.ConversationForm_Closing); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.tsMessage.ResumeLayout(false); + this.tsMessage.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.displayOwner)).EndInit(); + this.panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.displayUser)).EndInit(); + this.ResumeLayout(false); + + } + #endregion + + private Messenger _messenger = null; + private ConversationID activeconversationID = null; + + bool isYIM = false; + + + public ConversationID ConversationID + { + get + { + return activeconversationID; + } + + private set + { + activeconversationID = value; + } + } + + protected ConversationForm() + { + } + + /// + /// For sending and receiving YIM messages. + /// + /// + /// + public ConversationForm(Messenger messenger, Contact contact, ConversationID convId) + { + InitializeComponent(); + + _messenger = messenger; + activeconversationID = convId; + + isYIM = (ConversationID.NetworkType == ClientType.EmailMember); + + if (isYIM) + { + btnActivityTest.Enabled = false; + btnCustomEmoticon.Enabled = false; + btnInviteUsers.Enabled = false; + btnSendFiles.Enabled = false; + } + } + + public void OnMessageReceived(object sender, MessageArrivedEventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(OnMessageReceived), new object[] { sender, e }); + } + else + { + switch (e.MessageType) + { + case NetworkMessageType.Nudge: + MakeVisible(sender, e); + PrintNudge(e.Sender); + break; + case NetworkMessageType.Text: + MakeVisible(sender, e); + PrintText(e.Sender, (e as TextMessageArrivedEventArgs).TextMessage); + break; + case NetworkMessageType.Emoticon: + { + Emoticon emo = (e as EmoticonArrivedEventArgs).Emoticon; + if (emo != null) + { + MemoryStream ms = new MemoryStream(); + byte[] byt = new byte[emo.OpenStream().Length]; + emo.OpenStream().Seek(0, SeekOrigin.Begin); + emo.OpenStream().Read(byt, 0, byt.Length); + ms.Write(byt, 0, byt.Length); + + richTextHistory.Emotions[emo.Shortcut] = new Bitmap(Image.FromStream(ms)); + + ms.Close(); + } + + while (richTextHistory.HasEmotion) + { + richTextHistory.InsertEmotion(); + } + } + break; + } + } + } + + /// + /// Clean up any resources being used. + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (components != null) + { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + } + + + private void inputTextBox_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e) + { + if ((e.KeyCode == Keys.Return) && (e.Alt || e.Control || e.Shift)) + { + return; + } + + try + { + _messenger.MessageManager.SendTyping(ConversationID); + + } + catch (Exception) + { + } + + if (e.KeyCode == Keys.Return) + { + if (!inputTextBox.Text.Equals(String.Empty)) + { + bMessageSend.PerformClick(); + } + e.Handled = true; + } + + + } + + private void inputTextBox_KeyPress(object sender, KeyPressEventArgs e) + { + if (e.KeyChar == '\x001b') + { + Close(); + } + else if ((e.KeyChar == '\r') && inputTextBox.Text.Equals(string.Empty)) + { + e.Handled = true; + } + } + + private void MakeVisible(object sender, EventArgs e) + { + Show(); + } + + private void PrintNudge(Contact sender) + { + DisplaySystemMessage(sender.Name + " has sent a nudge!"); + PerformNudge(); + } + + + public void DisplaySystemMessage(string systemMessage) + { + richTextHistory.SelectionColor = Color.Red; + richTextHistory.SelectionFont = new Font("Verdana", 8f, FontStyle.Bold); + richTextHistory.SelectionIndent = 30; + richTextHistory.AppendText("* " + systemMessage + " *"); + richTextHistory.SelectionColor = Color.Black; + richTextHistory.SelectionIndent = 0; + richTextHistory.SelectionFont = new Font("Verdana", 8f); + richTextHistory.AppendText(Environment.NewLine); + richTextHistory.ScrollToCaret(); + } + + + private void ConversationForm_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + ConversationID.RemoteOwner.DisplayImageChanged -= Contact_DisplayImageChanged; + ConversationID.RemoteOwner.DisplayImageContextChanged -= Contact_DisplayImageConextChanged; + _messenger.MessageManager.EndConversation(activeconversationID); + } + + private void PrintText(Contact c, TextMessage message) + { + richTextHistory.SelectionColor = Color.Navy; + richTextHistory.SelectionIndent = 0; + richTextHistory.AppendText("[" + DateTime.Now.ToLongTimeString() + "]" + " "); + richTextHistory.SelectionColor = c.Mail == _messenger.ContactList.Owner.Mail ? Color.Blue : Color.Black; + richTextHistory.AppendText(c.Name + " <" + c.Mail + ">" + Environment.NewLine); + richTextHistory.SelectionColor = message.Color; + richTextHistory.SelectionIndent = 10; + richTextHistory.AppendText(message.Text); + richTextHistory.AppendText(Environment.NewLine); + richTextHistory.ScrollToCaret(); + + while (richTextHistory.HasEmotion) + { + richTextHistory.InsertEmotion(); + } + } + + private Image CreateImageFromColor(Color color, Size buttonSize) + { + Bitmap bitmap = new Bitmap(buttonSize.Width, buttonSize.Height); + using (Graphics graphics = Graphics.FromImage(bitmap)) + { + graphics.Clear(color); + } + return bitmap; + } + + private void UpdateTextFonts() + { + FontStyle fontStyle = FontStyle.Regular; + + if (bMessageBold.Checked) + fontStyle |= FontStyle.Bold; + if (bMessageItalic.Checked) + fontStyle |= FontStyle.Italic; + if (bMessageUnderline.Checked) + fontStyle |= FontStyle.Underline; + + Single fontSize = Single.Parse(cbMessageFontSize.Text); + Font messageFont = null; + + CreateFont: + try + { + messageFont = new Font(cbMessageFontName.Text, fontSize, fontStyle, GraphicsUnit.Point); + } + catch (ArgumentException) + { + fontStyle++; + if (fontStyle <= (FontStyle.Strikeout | FontStyle.Underline | FontStyle.Italic | FontStyle.Bold)) + goto CreateFont; + } + + if (messageFont == null) + return; + + bMessageBold.Checked = (fontStyle & FontStyle.Bold) != FontStyle.Regular; + bMessageItalic.Checked = (fontStyle & FontStyle.Italic) != FontStyle.Regular; + bMessageUnderline.Checked = (fontStyle & FontStyle.Underline) != FontStyle.Regular; + + richTextHistory.Font = new Font(richTextHistory.Font.FontFamily, messageFont.Size); + inputTextBox.Font = messageFont; + } + + private void ConversationForm_Load(object sender, EventArgs e) + { + Text = "Conversation with " + ConversationID.RemoteOwner.Mail + " - MSNPSharp"; + Icon = (Icon)((ConversationID.RemoteOwner.ClientType == ClientType.PassportMember) ? Properties.Resources.msn_ico : Properties.Resources.yahoo_ico); + + if (_messenger.ContactList.Owner.DisplayImage.Image != null) + displayOwner.Image = _messenger.ContactList.Owner.DisplayImage.Image; + else + displayOwner.Image = DisplayImage.DefaultImage; + + lock (richTextHistory.Emotions) + { + richTextHistory.Emotions[":)"] = Properties.Resources.smiley; + richTextHistory.Emotions[":d"] = Properties.Resources.biggrin; + richTextHistory.Emotions[":("] = Properties.Resources.sad; + richTextHistory.Emotions[";)"] = Properties.Resources.wink; + richTextHistory.Emotions[":p"] = Properties.Resources.tongueout; + } + + foreach (FontFamily ff in FontFamily.Families) + { + cbMessageFontName.Items.Add(ff.Name); + } + cbMessageFontName.Text = inputTextBox.Font.Name; + cbMessageFontSize.Text = inputTextBox.Font.Size.ToString(); + bMessageFontColor.Image = CreateImageFromColor(inputTextBox.ForeColor, inputTextBox.Size); + + cbMessageFontName.Tag = cbMessageFontName.Text; + cbMessageFontSize.Tag = cbMessageFontSize.Text; + + UpdateTextFonts(); + + inputTextBox.Select(); + } + + private void ConversationForm_Shown(object sender, EventArgs e) + { + if (!isYIM) + { + if (ConversationID.RemoteOwner.DisplayImage.Image != null) + displayUser.Image = ConversationID.RemoteOwner.DisplayImage.Image; + else + displayUser.Image = DisplayImage.DefaultImage; + } + else + displayUser.Image = Properties.Resources.YahooMessenger_logo.Clone() as Image; + + ConversationID.RemoteOwner.DisplayImageChanged += new EventHandler(Contact_DisplayImageChanged); + ConversationID.RemoteOwner.DisplayImageContextChanged += new EventHandler(Contact_DisplayImageConextChanged); + + // request the image, if not already available + if (ConversationID.RemoteOwner.Status != PresenceStatus.Offline) + { + if (ConversationID.RemoteOwner.DisplayImage != ConversationID.RemoteOwner.UserTileLocation) + { + try + { + RequestDisplayImage(ConversationID.RemoteOwner, null); + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, ex.Message + "\r\n StackTrace: " + ex.StackTrace); + } + } + + + } + } + + private void RequestDisplayImage(Contact remoteContact, DisplayImage updateImage) + { + if (remoteContact.ClientType == ClientType.PassportMember && + updateImage != remoteContact.UserTileLocation) + { + if (updateImage == null) + updateImage = remoteContact.DisplayImage; + + // by sending an invitation a P2PTransferSession is automatically created. + // the session object takes care of the actual data transfer to the remote client, + // in contrast to the msnslpHandler object, which only deals with the protocol chatting. + P2PTransferSession session = _messenger.RequestMsnObject(remoteContact, updateImage); + } + } + + private void Contact_DisplayImageConextChanged(object sender, DisplayImageChangedEventArgs e) + { + try + { + RequestDisplayImage(ConversationID.RemoteOwner, null); + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, ex.Message + "\r\n StackTrace: " + ex.StackTrace); + } + } + + private void Contact_DisplayImageChanged(object sender, DisplayImageChangedEventArgs e) + { + if (displayUser.InvokeRequired) + { + Invoke(new EventHandler(Contact_DisplayImageChanged), new object[] { sender, e }); + } + else + { + displayUser.Image = e.NewDisplayImage.Image; + } + } + + private void emotionDropDown_Click(object sender, EventArgs args) + { + ToolStripItem item = (ToolStripItem)sender; + inputTextBox.AppendText(item.ToolTipText); + inputTextBox.Focus(); + } + + private void PerformNudge() + { + Stopwatch stopwatch = new Stopwatch(); + + Random rnd = new Random(); + int x = Left; + int y = Top; + + stopwatch.Start(); + while (stopwatch.ElapsedMilliseconds < 500) + { + Left = rnd.Next(Location.X - 5, Location.X + 5); + Top = rnd.Next(Location.Y - 1, Location.Y + 1); + + System.Threading.Thread.Sleep(10); + Application.DoEvents(); + } + stopwatch.Stop(); + + Left = x; + Top = y; + } + + private void bMessageSend_Click(object sender, EventArgs e) + { + if (inputTextBox.Text.Length == 0) + return; + + TextMessage message = new TextMessage(inputTextBox.Text); + message.Font = inputTextBox.Font.Name; + message.Color = inputTextBox.ForeColor; + + if (inputTextBox.Font.Bold) + message.Decorations |= TextDecorations.Bold; + if (inputTextBox.Font.Italic) + message.Decorations |= TextDecorations.Italic; + if (inputTextBox.Font.Underline) + message.Decorations |= TextDecorations.Underline; + + inputTextBox.Clear(); + inputTextBox.Focus(); + + + ConversationID = _messenger.MessageManager.SendTextMessage(ConversationID, message); + PrintText(_messenger.ContactList.Owner, message); + + + } + + private void btnInviteUsers_Click(object sender, EventArgs e) + { + int x = Location.X + 10 + btnInviteUsers.Width; + int y = Location.Y + 10 + btnInviteUsers.Height + 20; + + onlineUsersDropDown.Items.Clear(); + foreach (Contact c in _messenger.ContactList.Forward) + { + if (c.Online && c.ClientType == ClientType.PassportMember) + { + onlineUsersDropDown.Items.Add(c.Mail, null, onlineUsersDropDown_Click).ToolTipText = c.Mail; + } + } + + onlineUsersDropDown.Show(x, y); + onlineUsersDropDown.Focus(); + } + + private void onlineUsersDropDown_Click(object sender, EventArgs args) + { + ToolStripItem item = (ToolStripItem)sender; + if (_messenger.ContactList.HasContact(item.ToolTipText, ClientType.PassportMember)) + { + activeconversationID = _messenger.MessageManager.InviteContactToConversation(activeconversationID, _messenger.ContactList.GetContact(item.ToolTipText)); + } + else + { + DisplaySystemMessage("Cannot find PassportMember: " + item.ToolTipText); + } + } + + private void bMessageSendNudge_Click(object sender, EventArgs e) + { + try + { + ConversationID = _messenger.MessageManager.SendNudge(ConversationID); + DisplaySystemMessage("You send a nudge."); + PerformNudge(); + } + catch (Exception) + { + + DisplaySystemMessage("Remote contact not online."); + } + } + + private void bMessageSendFiles_Click(object sender, EventArgs e) + { + if (ConversationID.RemoteOwner.Online == false || ConversationID.RemoteOwner == null) + { + DisplaySystemMessage("All contacts are offline or this contact doesn't support receiving files."); + return; + } + + if (openFileDialog.ShowDialog() == DialogResult.OK) + { + + try + { + + foreach (string filename in openFileDialog.FileNames) + { + FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); + P2PTransferSession session = _messenger.SendFile(ConversationID.RemoteOwner, filename, fileStream); + } + } + catch (MSNPSharpException ex) + { + MessageBox.Show(ex.Message); + } + + + + } + } + + private void bMessageSendCustomEmoticon_Click(object sender, EventArgs e) + { + if (openCustomEmoticonDialog.ShowDialog() != DialogResult.OK) + return; + + MemoryStream mem = new MemoryStream(); + Bitmap img = new Bitmap(Image.FromFile(openCustomEmoticonDialog.FileName)); + img.Save(mem, ImageFormat.Png); + Emoticon emotest = new Emoticon(_messenger.Owner.Mail, mem, Path.GetFileName(openCustomEmoticonDialog.FileName), Path.GetFileName(openCustomEmoticonDialog.FileName)); + MSNObjectCatalog.GetInstance().Add(emotest); + List emolist = new List(); + emolist.Add(emotest); + + if (!richTextHistory.Emotions.ContainsKey(emotest.Shortcut)) + { + richTextHistory.Emotions[emotest.Shortcut] = img; + } + + try + { + ConversationID = _messenger.MessageManager.SendEmoticonDefinitions(ConversationID, emolist, EmoticonType.StaticEmoticon); + TextMessage emotxt = new TextMessage("Hey, this is a custom emoticon: " + emotest.Shortcut); + ConversationID = _messenger.MessageManager.SendTextMessage(ConversationID, emotxt); + DisplaySystemMessage("You send a custom emoticon with text message: Hey, this is a custom emoticon: [" + emotest.Shortcut + "]."); + } + catch (Exception) + { + if (!isYIM) + DisplaySystemMessage("Remote contact not online, emoticon will not be sent."); + } + } + + private void bMessageBoldItalicUnderline_CheckedChanged(object sender, EventArgs e) + { + UpdateTextFonts(); + inputTextBox.Select(); + } + + private void bMessageFontColor_Click(object sender, EventArgs e) + { + if (dlgColor.ShowDialog() == DialogResult.OK) + { + bMessageFontColor.Image = CreateImageFromColor(dlgColor.Color, bMessageFontColor.Image.Size); + inputTextBox.ForeColor = dlgColor.Color; + } + } + + private void cbMessageFontName_SelectedIndexChanged(object sender, EventArgs e) + { + Validate(); + } + + private void cbMessageFontName_Validated(object sender, EventArgs e) + { + cbMessageFontName.Tag = cbMessageFontName.Text; + UpdateTextFonts(); + inputTextBox.Select(); + } + + private void cbMessageFontName_Validating(object sender, CancelEventArgs e) + { + if (cbMessageFontName.FindStringExact(cbMessageFontName.Text) == -1 && cbMessageFontName.Tag != null) + { + cbMessageFontName.Text = cbMessageFontName.Tag.ToString(); + } + + } + + private void cbMessageFontSize_SelectedIndexChanged(object sender, EventArgs e) + { + Validate(); + } + + private void cbMessageFontSize_Validated(object sender, EventArgs e) + { + cbMessageFontSize.Tag = cbMessageFontSize.Text; + UpdateTextFonts(); + inputTextBox.Select(); + } + + private void cbMessageFontSize_Validating(object sender, CancelEventArgs e) + { + float fontSize = float.MinValue; + float.TryParse(cbMessageFontSize.Text, out fontSize); + + if (fontSize < 8f || fontSize > 72f && cbMessageFontSize.Tag != null) + { + cbMessageFontSize.Text = cbMessageFontSize.Tag.ToString(); + } + } + + private void MSNSLPHandler_TransferSessionClosed(object sender, P2PTransferSessionEventArgs e) + { + if (!richTextHistory.InvokeRequired) + { + DisplaySystemMessage("Activity session closed."); + } + else + { + richTextHistory.Invoke(new EventHandler(MSNSLPHandler_TransferSessionClosed), new object[] { sender,e }); + } + } + + private void btnActivityTest_Click(object sender, EventArgs e) + { + String activityID = "7"; //"20521364"; //The activityID of Music Mix activity. + String activityName = "Activity Test"; //Th name of acticvity + MSNSLPHandler msnslpHandler = _messenger.GetMSNSLPHandler(ConversationID.RemoteOwner); + P2PTransferSession session = msnslpHandler.SendInvitation(_messenger.ContactList.Owner, ConversationID.RemoteOwner, activityID, activityName, @"http://code.google.com/p/msnp-sharp"); + + msnslpHandler.TransferSessionClosed += delegate(object s, P2PTransferSessionEventArgs ea) + { + if (ea.TransferSession == session) + MSNSLPHandler_TransferSessionClosed(s, ea); + }; + } + } +}; diff --git a/Example/ConversationForm.resx b/Example/ConversationForm.resx new file mode 100644 index 0000000..67504b6 --- /dev/null +++ b/Example/ConversationForm.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 274, 14 + + + 397, 18 + + + 17, 17 + + + 158, 20 + + + 17, 57 + + \ No newline at end of file diff --git a/Example/DotMSNClient.Designer.cs b/Example/DotMSNClient.Designer.cs new file mode 100644 index 0000000..00d27e7 --- /dev/null +++ b/Example/DotMSNClient.Designer.cs @@ -0,0 +1,876 @@ +using System.Windows.Forms; + +namespace MSNPSharpClient +{ + partial class ClientForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.ImageList1 = new System.Windows.Forms.ImageList(this.components); + this.userMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); + this.sendIMMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.sendOIMMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.sendMIMMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem3 = new System.Windows.Forms.ToolStripSeparator(); + this.importContactsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.createCircleMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator(); + this.blockMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.unblockMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.deleteMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); + this.openImageDialog = new System.Windows.Forms.OpenFileDialog(); + this.tmrKeepOnLine = new System.Windows.Forms.Timer(this.components); + this.tmrNews = new System.Windows.Forms.Timer(this.components); + this.sortContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.toolStripSortByStatus = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSortBygroup = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripDeleteGroup = new System.Windows.Forms.ToolStripMenuItem(); + this.groupContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.toolTipChangePhoto = new System.Windows.Forms.ToolTip(this.components); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.WhatsUpPanel = new System.Windows.Forms.Panel(); + this.lblNewsLink = new System.Windows.Forms.LinkLabel(); + this.lblNews = new System.Windows.Forms.Label(); + this.pbNewsPicture = new System.Windows.Forms.PictureBox(); + this.cmdNext = new System.Windows.Forms.Button(); + this.cmdPrev = new System.Windows.Forms.Button(); + this.lblWhatsup = new System.Windows.Forms.Label(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.propertyGrid = new System.Windows.Forms.PropertyGrid(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.pnlTreeViewsContainer = new System.Windows.Forms.Panel(); + this.treeViewFilterList = new System.Windows.Forms.TreeView(); + this.treeViewFavoriteList = new System.Windows.Forms.TreeView(); + this.SortPanel = new System.Windows.Forms.Panel(); + this.txtSearch = new System.Windows.Forms.TextBox(); + this.btnAddNew = new System.Windows.Forms.Button(); + this.btnSortBy = new System.Windows.Forms.Button(); + this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); + this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); + this.tableLayoutPanel5 = new System.Windows.Forms.TableLayoutPanel(); + this.displayImageBox = new System.Windows.Forms.PictureBox(); + this.panel1 = new System.Windows.Forms.Panel(); + this.tableLayoutPanel6 = new System.Windows.Forms.TableLayoutPanel(); + this.pnlLogin = new System.Windows.Forms.Panel(); + this.pnlNameAndPM = new System.Windows.Forms.Panel(); + this.btnSetMusic = new System.Windows.Forms.Button(); + this.lblPM = new System.Windows.Forms.TextBox(); + this.lblName = new System.Windows.Forms.TextBox(); + this.cbRobotMode = new System.Windows.Forms.CheckBox(); + this.accountTextBox = new System.Windows.Forms.TextBox(); + this.loginButton = new System.Windows.Forms.Button(); + this.passwordTextBox = new System.Windows.Forms.TextBox(); + this.tableLayoutPanel7 = new System.Windows.Forms.TableLayoutPanel(); + this.comboPlaces = new System.Windows.Forms.ComboBox(); + this.comboStatus = new System.Windows.Forms.ComboBox(); + this.statusBar = new System.Windows.Forms.Label(); + this.userMenuStrip.SuspendLayout(); + this.sortContextMenu.SuspendLayout(); + this.groupContextMenu.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.WhatsUpPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pbNewsPicture)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + this.pnlTreeViewsContainer.SuspendLayout(); + this.SortPanel.SuspendLayout(); + this.tableLayoutPanel3.SuspendLayout(); + this.tableLayoutPanel4.SuspendLayout(); + this.tableLayoutPanel5.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.displayImageBox)).BeginInit(); + this.panel1.SuspendLayout(); + this.tableLayoutPanel6.SuspendLayout(); + this.pnlLogin.SuspendLayout(); + this.pnlNameAndPM.SuspendLayout(); + this.tableLayoutPanel7.SuspendLayout(); + this.SuspendLayout(); + // + // ImageList1 + // + this.ImageList1.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit; + this.ImageList1.ImageSize = new System.Drawing.Size(10, 10); + this.ImageList1.TransparentColor = System.Drawing.Color.Transparent; + // + // userMenuStrip + // + this.userMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.sendIMMenuItem, + this.sendOIMMenuItem, + this.sendMIMMenuItem, + this.toolStripMenuItem3, + this.importContactsMenuItem, + this.createCircleMenuItem, + this.toolStripMenuItem2, + this.blockMenuItem, + this.unblockMenuItem, + this.deleteMenuItem}); + this.userMenuStrip.Name = "contextMenuStrip1"; + this.userMenuStrip.Size = new System.Drawing.Size(201, 192); + // + // sendIMMenuItem + // + this.sendIMMenuItem.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold); + this.sendIMMenuItem.Name = "sendIMMenuItem"; + this.sendIMMenuItem.Size = new System.Drawing.Size(200, 22); + this.sendIMMenuItem.Text = "Send Instant Message"; + this.sendIMMenuItem.Click += new System.EventHandler(this.sendMessageToolStripMenuItem_Click); + // + // sendOIMMenuItem + // + this.sendOIMMenuItem.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold); + this.sendOIMMenuItem.Name = "sendOIMMenuItem"; + this.sendOIMMenuItem.Size = new System.Drawing.Size(200, 22); + this.sendOIMMenuItem.Text = "Send Offline Message"; + this.sendOIMMenuItem.Click += new System.EventHandler(this.sendOfflineMessageToolStripMenuItem_Click); + // + // sendMIMMenuItem + // + this.sendMIMMenuItem.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold); + this.sendMIMMenuItem.Name = "sendMIMMenuItem"; + this.sendMIMMenuItem.Size = new System.Drawing.Size(200, 22); + this.sendMIMMenuItem.Text = "Send Mobile Message"; + this.sendMIMMenuItem.Click += new System.EventHandler(this.sendMIMMenuItem_Click); + // + // toolStripMenuItem3 + // + this.toolStripMenuItem3.Name = "toolStripMenuItem3"; + this.toolStripMenuItem3.Size = new System.Drawing.Size(197, 6); + // + // importContactsMenuItem + // + this.importContactsMenuItem.Name = "importContactsMenuItem"; + this.importContactsMenuItem.Size = new System.Drawing.Size(200, 22); + this.importContactsMenuItem.Text = "Import Contacts"; + this.importContactsMenuItem.Click += new System.EventHandler(this.importContactsMenuItem_Click); + // + // createCircleMenuItem + // + this.createCircleMenuItem.Name = "createCircleMenuItem"; + this.createCircleMenuItem.Size = new System.Drawing.Size(200, 22); + this.createCircleMenuItem.Text = "Circle Tests"; + this.createCircleMenuItem.Click += new System.EventHandler(this.createCircleMenuItem_Click); + // + // toolStripMenuItem2 + // + this.toolStripMenuItem2.Name = "toolStripMenuItem2"; + this.toolStripMenuItem2.Size = new System.Drawing.Size(197, 6); + // + // blockMenuItem + // + this.blockMenuItem.Name = "blockMenuItem"; + this.blockMenuItem.Size = new System.Drawing.Size(200, 22); + this.blockMenuItem.Text = "Block"; + this.blockMenuItem.Click += new System.EventHandler(this.blockToolStripMenuItem_Click); + // + // unblockMenuItem + // + this.unblockMenuItem.Name = "unblockMenuItem"; + this.unblockMenuItem.Size = new System.Drawing.Size(200, 22); + this.unblockMenuItem.Text = "Unblock"; + this.unblockMenuItem.Click += new System.EventHandler(this.unblockMenuItem_Click); + // + // deleteMenuItem + // + this.deleteMenuItem.Name = "deleteMenuItem"; + this.deleteMenuItem.Size = new System.Drawing.Size(200, 22); + this.deleteMenuItem.Text = "Delete"; + this.deleteMenuItem.Click += new System.EventHandler(this.deleteMenuItem_Click); + // + // openFileDialog + // + this.openFileDialog.Multiselect = true; + // + // openImageDialog + // + this.openImageDialog.Filter = "Supported Images|*.png;*.jpg;*.jpeg;*.gif"; + this.openImageDialog.Multiselect = true; + this.openImageDialog.Title = "Select display image"; + // + // tmrKeepOnLine + // + this.tmrKeepOnLine.Interval = 1000; + // + // tmrNews + // + this.tmrNews.Interval = 5000; + this.tmrNews.Tick += new System.EventHandler(this.tmrNews_Tick); + // + // sortContextMenu + // + this.sortContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripSortByStatus, + this.toolStripSortBygroup}); + this.sortContextMenu.Name = "sortContextMenu"; + this.sortContextMenu.ShowCheckMargin = true; + this.sortContextMenu.ShowImageMargin = false; + this.sortContextMenu.Size = new System.Drawing.Size(140, 48); + // + // toolStripSortByStatus + // + this.toolStripSortByStatus.Checked = true; + this.toolStripSortByStatus.CheckOnClick = true; + this.toolStripSortByStatus.CheckState = System.Windows.Forms.CheckState.Checked; + this.toolStripSortByStatus.Name = "toolStripSortByStatus"; + this.toolStripSortByStatus.ShowShortcutKeys = false; + this.toolStripSortByStatus.Size = new System.Drawing.Size(139, 22); + this.toolStripSortByStatus.Text = "Sort by status"; + this.toolStripSortByStatus.Click += new System.EventHandler(this.toolStripSortByStatus_Click); + // + // toolStripSortBygroup + // + this.toolStripSortBygroup.CheckOnClick = true; + this.toolStripSortBygroup.Name = "toolStripSortBygroup"; + this.toolStripSortBygroup.ShowShortcutKeys = false; + this.toolStripSortBygroup.Size = new System.Drawing.Size(139, 22); + this.toolStripSortBygroup.Text = "Sort by group"; + this.toolStripSortBygroup.Click += new System.EventHandler(this.toolStripSortBygroup_Click); + // + // toolStripDeleteGroup + // + this.toolStripDeleteGroup.Name = "toolStripDeleteGroup"; + this.toolStripDeleteGroup.Size = new System.Drawing.Size(142, 22); + this.toolStripDeleteGroup.Text = "Delete group"; + this.toolStripDeleteGroup.Click += new System.EventHandler(this.toolStripDeleteGroup_Click); + // + // groupContextMenu + // + this.groupContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripDeleteGroup}); + this.groupContextMenu.Name = "sortContextMenu"; + this.groupContextMenu.ShowCheckMargin = true; + this.groupContextMenu.ShowImageMargin = false; + this.groupContextMenu.Size = new System.Drawing.Size(143, 26); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Controls.Add(this.WhatsUpPanel, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.splitContainer1, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel3, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.statusBar, 0, 3); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 4; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 128F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 57F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 30F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(643, 634); + this.tableLayoutPanel1.TabIndex = 3; + // + // WhatsUpPanel + // + this.WhatsUpPanel.BackColor = System.Drawing.Color.White; + this.WhatsUpPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.WhatsUpPanel.Controls.Add(this.lblNewsLink); + this.WhatsUpPanel.Controls.Add(this.lblNews); + this.WhatsUpPanel.Controls.Add(this.pbNewsPicture); + this.WhatsUpPanel.Controls.Add(this.cmdNext); + this.WhatsUpPanel.Controls.Add(this.cmdPrev); + this.WhatsUpPanel.Controls.Add(this.lblWhatsup); + this.WhatsUpPanel.Dock = System.Windows.Forms.DockStyle.Bottom; + this.WhatsUpPanel.Location = new System.Drawing.Point(3, 551); + this.WhatsUpPanel.Name = "WhatsUpPanel"; + this.WhatsUpPanel.Size = new System.Drawing.Size(637, 50); + this.WhatsUpPanel.TabIndex = 8; + // + // lblNewsLink + // + this.lblNewsLink.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.lblNewsLink.Location = new System.Drawing.Point(506, 25); + this.lblNewsLink.Name = "lblNewsLink"; + this.lblNewsLink.Size = new System.Drawing.Size(69, 21); + this.lblNewsLink.TabIndex = 5; + this.lblNewsLink.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.lblNewsLink.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.lblNewsLink_LinkClicked); + // + // lblNews + // + this.lblNews.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.lblNews.AutoEllipsis = true; + this.lblNews.BackColor = System.Drawing.Color.Transparent; + this.lblNews.Location = new System.Drawing.Point(97, 3); + this.lblNews.Name = "lblNews"; + this.lblNews.Size = new System.Drawing.Size(402, 42); + this.lblNews.TabIndex = 4; + this.lblNews.Text = " *"; + this.lblNews.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // pbNewsPicture + // + this.pbNewsPicture.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.pbNewsPicture.BackColor = System.Drawing.Color.Transparent; + this.pbNewsPicture.Cursor = System.Windows.Forms.Cursors.Hand; + this.pbNewsPicture.Location = new System.Drawing.Point(589, 1); + this.pbNewsPicture.Name = "pbNewsPicture"; + this.pbNewsPicture.Size = new System.Drawing.Size(45, 45); + this.pbNewsPicture.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.pbNewsPicture.TabIndex = 3; + this.pbNewsPicture.TabStop = false; + // + // cmdNext + // + this.cmdNext.Location = new System.Drawing.Point(42, 22); + this.cmdNext.Name = "cmdNext"; + this.cmdNext.Size = new System.Drawing.Size(22, 22); + this.cmdNext.TabIndex = 2; + this.cmdNext.Text = ">"; + this.cmdNext.UseVisualStyleBackColor = true; + this.cmdNext.Click += new System.EventHandler(this.cmdNext_Click); + // + // cmdPrev + // + this.cmdPrev.Location = new System.Drawing.Point(15, 22); + this.cmdPrev.Name = "cmdPrev"; + this.cmdPrev.Size = new System.Drawing.Size(22, 22); + this.cmdPrev.TabIndex = 1; + this.cmdPrev.Text = "<"; + this.cmdPrev.UseVisualStyleBackColor = true; + this.cmdPrev.Click += new System.EventHandler(this.cmdPrev_Click); + // + // lblWhatsup + // + this.lblWhatsup.AutoSize = true; + this.lblWhatsup.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(162))); + this.lblWhatsup.Location = new System.Drawing.Point(11, 3); + this.lblWhatsup.Name = "lblWhatsup"; + this.lblWhatsup.Size = new System.Drawing.Size(66, 13); + this.lblWhatsup.TabIndex = 0; + this.lblWhatsup.Text = "What\'s Up"; + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(3, 131); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.Controls.Add(this.propertyGrid); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel2); + this.splitContainer1.Size = new System.Drawing.Size(637, 413); + this.splitContainer1.SplitterDistance = 252; + this.splitContainer1.TabIndex = 0; + // + // propertyGrid + // + this.propertyGrid.BackColor = System.Drawing.Color.White; + this.propertyGrid.CommandsBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(128))))); + this.propertyGrid.Dock = System.Windows.Forms.DockStyle.Fill; + this.propertyGrid.HelpBackColor = System.Drawing.Color.White; + this.propertyGrid.LineColor = System.Drawing.SystemColors.ScrollBar; + this.propertyGrid.Location = new System.Drawing.Point(0, 0); + this.propertyGrid.Name = "propertyGrid"; + this.propertyGrid.Size = new System.Drawing.Size(252, 413); + this.propertyGrid.TabIndex = 5; + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.ColumnCount = 1; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.Controls.Add(this.pnlTreeViewsContainer, 0, 1); + this.tableLayoutPanel2.Controls.Add(this.SortPanel, 0, 0); + this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(1); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 2; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 29F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(381, 413); + this.tableLayoutPanel2.TabIndex = 0; + // + // pnlTreeViewsContainer + // + this.pnlTreeViewsContainer.Controls.Add(this.treeViewFilterList); + this.pnlTreeViewsContainer.Controls.Add(this.treeViewFavoriteList); + this.pnlTreeViewsContainer.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlTreeViewsContainer.Location = new System.Drawing.Point(3, 32); + this.pnlTreeViewsContainer.Name = "pnlTreeViewsContainer"; + this.pnlTreeViewsContainer.Size = new System.Drawing.Size(375, 378); + this.pnlTreeViewsContainer.TabIndex = 3; + // + // treeViewFilterList + // + this.treeViewFilterList.BackColor = System.Drawing.Color.White; + this.treeViewFilterList.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.treeViewFilterList.Dock = System.Windows.Forms.DockStyle.Fill; + this.treeViewFilterList.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(162))); + this.treeViewFilterList.FullRowSelect = true; + this.treeViewFilterList.HideSelection = false; + this.treeViewFilterList.Indent = 20; + this.treeViewFilterList.ItemHeight = 20; + this.treeViewFilterList.Location = new System.Drawing.Point(0, 0); + this.treeViewFilterList.Name = "treeViewFilterList"; + this.treeViewFilterList.ShowLines = false; + this.treeViewFilterList.ShowPlusMinus = false; + this.treeViewFilterList.ShowRootLines = false; + this.treeViewFilterList.Size = new System.Drawing.Size(375, 378); + this.treeViewFilterList.TabIndex = 5; + this.treeViewFilterList.Visible = false; + this.treeViewFilterList.NodeMouseDoubleClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.treeView1_NodeMouseDoubleClick); + this.treeViewFilterList.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.treeView1_NodeMouseClick); + // + // treeViewFavoriteList + // + this.treeViewFavoriteList.AllowDrop = true; + this.treeViewFavoriteList.BackColor = System.Drawing.Color.White; + this.treeViewFavoriteList.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.treeViewFavoriteList.Dock = System.Windows.Forms.DockStyle.Fill; + this.treeViewFavoriteList.Font = new System.Drawing.Font("Tahoma", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(162))); + this.treeViewFavoriteList.FullRowSelect = true; + this.treeViewFavoriteList.HideSelection = false; + this.treeViewFavoriteList.ImageIndex = 0; + this.treeViewFavoriteList.ImageList = this.ImageList1; + this.treeViewFavoriteList.Indent = 15; + this.treeViewFavoriteList.ItemHeight = 20; + this.treeViewFavoriteList.Location = new System.Drawing.Point(0, 0); + this.treeViewFavoriteList.Name = "treeViewFavoriteList"; + this.treeViewFavoriteList.SelectedImageIndex = 0; + this.treeViewFavoriteList.ShowLines = false; + this.treeViewFavoriteList.ShowPlusMinus = false; + this.treeViewFavoriteList.ShowRootLines = false; + this.treeViewFavoriteList.Size = new System.Drawing.Size(375, 378); + this.treeViewFavoriteList.TabIndex = 4; + this.treeViewFavoriteList.NodeMouseDoubleClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.treeView1_NodeMouseDoubleClick); + this.treeViewFavoriteList.DragDrop += new System.Windows.Forms.DragEventHandler(this.treeViewFavoriteList_DragDrop); + this.treeViewFavoriteList.DragEnter += new System.Windows.Forms.DragEventHandler(this.treeViewFavoriteList_DragEnter); + this.treeViewFavoriteList.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.treeView1_NodeMouseClick); + this.treeViewFavoriteList.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.treeViewFavoriteList_ItemDrag); + this.treeViewFavoriteList.DragOver += new System.Windows.Forms.DragEventHandler(this.treeViewFavoriteList_DragOver); + // + // SortPanel + // + this.SortPanel.BackColor = System.Drawing.Color.White; + this.SortPanel.Controls.Add(this.txtSearch); + this.SortPanel.Controls.Add(this.btnAddNew); + this.SortPanel.Controls.Add(this.btnSortBy); + this.SortPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.SortPanel.Location = new System.Drawing.Point(1, 1); + this.SortPanel.Margin = new System.Windows.Forms.Padding(1); + this.SortPanel.Name = "SortPanel"; + this.SortPanel.Size = new System.Drawing.Size(379, 27); + this.SortPanel.TabIndex = 2; + // + // txtSearch + // + this.txtSearch.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtSearch.ForeColor = System.Drawing.SystemColors.ScrollBar; + this.txtSearch.Location = new System.Drawing.Point(6, 4); + this.txtSearch.Name = "txtSearch"; + this.txtSearch.Size = new System.Drawing.Size(279, 21); + this.txtSearch.TabIndex = 9; + this.txtSearch.Text = "Search contacts"; + this.txtSearch.TextChanged += new System.EventHandler(this.txtSearch_TextChanged); + this.txtSearch.Leave += new System.EventHandler(this.txtSearch_Leave); + this.txtSearch.Enter += new System.EventHandler(this.txtSearch_Enter); + // + // btnAddNew + // + this.btnAddNew.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.btnAddNew.BackColor = System.Drawing.SystemColors.Control; + this.btnAddNew.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(162))); + this.btnAddNew.Location = new System.Drawing.Point(334, 2); + this.btnAddNew.Name = "btnAddNew"; + this.btnAddNew.Size = new System.Drawing.Size(44, 22); + this.btnAddNew.TabIndex = 7; + this.btnAddNew.Text = "+"; + this.btnAddNew.UseVisualStyleBackColor = true; + this.btnAddNew.Click += new System.EventHandler(this.btnAddNew_Click); + // + // btnSortBy + // + this.btnSortBy.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.btnSortBy.BackColor = System.Drawing.SystemColors.Control; + this.btnSortBy.Cursor = System.Windows.Forms.Cursors.Arrow; + this.btnSortBy.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(162))); + this.btnSortBy.Location = new System.Drawing.Point(290, 2); + this.btnSortBy.Name = "btnSortBy"; + this.btnSortBy.Size = new System.Drawing.Size(44, 22); + this.btnSortBy.TabIndex = 0; + this.btnSortBy.Text = "sort"; + this.btnSortBy.UseVisualStyleBackColor = true; + this.btnSortBy.Click += new System.EventHandler(this.btnSortBy_Click); + // + // tableLayoutPanel3 + // + this.tableLayoutPanel3.BackColor = System.Drawing.Color.White; + this.tableLayoutPanel3.BackgroundImage = global::MSNPSharpClient.Properties.Resources.app_banner; + this.tableLayoutPanel3.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; + this.tableLayoutPanel3.ColumnCount = 2; + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 380F)); + this.tableLayoutPanel3.Controls.Add(this.tableLayoutPanel4, 1, 0); + this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel3.Location = new System.Drawing.Point(3, 3); + this.tableLayoutPanel3.Name = "tableLayoutPanel3"; + this.tableLayoutPanel3.RowCount = 1; + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel3.Size = new System.Drawing.Size(637, 122); + this.tableLayoutPanel3.TabIndex = 9; + // + // tableLayoutPanel4 + // + this.tableLayoutPanel4.ColumnCount = 1; + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel4.Controls.Add(this.tableLayoutPanel5, 0, 0); + this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel4.Location = new System.Drawing.Point(260, 3); + this.tableLayoutPanel4.Name = "tableLayoutPanel4"; + this.tableLayoutPanel4.RowCount = 1; + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 126F)); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 126F)); + this.tableLayoutPanel4.Size = new System.Drawing.Size(374, 116); + this.tableLayoutPanel4.TabIndex = 0; + // + // tableLayoutPanel5 + // + this.tableLayoutPanel5.ColumnCount = 2; + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 87F)); + this.tableLayoutPanel5.Controls.Add(this.displayImageBox, 1, 0); + this.tableLayoutPanel5.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel5.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel5.Location = new System.Drawing.Point(3, 3); + this.tableLayoutPanel5.Name = "tableLayoutPanel5"; + this.tableLayoutPanel5.RowCount = 1; + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 120F)); + this.tableLayoutPanel5.Size = new System.Drawing.Size(368, 120); + this.tableLayoutPanel5.TabIndex = 0; + // + // displayImageBox + // + this.displayImageBox.BackColor = System.Drawing.Color.White; + this.displayImageBox.Cursor = System.Windows.Forms.Cursors.Hand; + this.displayImageBox.Location = new System.Drawing.Point(284, 3); + this.displayImageBox.Name = "displayImageBox"; + this.displayImageBox.Size = new System.Drawing.Size(80, 80); + this.displayImageBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; + this.displayImageBox.TabIndex = 3; + this.displayImageBox.TabStop = false; + this.displayImageBox.Click += new System.EventHandler(this.displayImageBox_Click); + // + // panel1 + // + this.panel1.Controls.Add(this.tableLayoutPanel6); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(3, 3); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(275, 114); + this.panel1.TabIndex = 4; + // + // tableLayoutPanel6 + // + this.tableLayoutPanel6.ColumnCount = 1; + this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel6.Controls.Add(this.pnlLogin, 0, 0); + this.tableLayoutPanel6.Controls.Add(this.tableLayoutPanel7, 0, 1); + this.tableLayoutPanel6.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel6.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel6.Name = "tableLayoutPanel6"; + this.tableLayoutPanel6.RowCount = 2; + this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 35F)); + this.tableLayoutPanel6.Size = new System.Drawing.Size(275, 114); + this.tableLayoutPanel6.TabIndex = 5; + // + // pnlLogin + // + this.pnlLogin.Controls.Add(this.pnlNameAndPM); + this.pnlLogin.Controls.Add(this.cbRobotMode); + this.pnlLogin.Controls.Add(this.accountTextBox); + this.pnlLogin.Controls.Add(this.loginButton); + this.pnlLogin.Controls.Add(this.passwordTextBox); + this.pnlLogin.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlLogin.Location = new System.Drawing.Point(3, 3); + this.pnlLogin.Name = "pnlLogin"; + this.pnlLogin.Size = new System.Drawing.Size(269, 73); + this.pnlLogin.TabIndex = 1; + // + // pnlNameAndPM + // + this.pnlNameAndPM.Controls.Add(this.btnSetMusic); + this.pnlNameAndPM.Controls.Add(this.lblPM); + this.pnlNameAndPM.Controls.Add(this.lblName); + this.pnlNameAndPM.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlNameAndPM.Location = new System.Drawing.Point(0, 0); + this.pnlNameAndPM.Name = "pnlNameAndPM"; + this.pnlNameAndPM.Size = new System.Drawing.Size(269, 73); + this.pnlNameAndPM.TabIndex = 15; + this.pnlNameAndPM.Visible = false; + // + // btnSetMusic + // + this.btnSetMusic.Location = new System.Drawing.Point(233, 25); + this.btnSetMusic.Name = "btnSetMusic"; + this.btnSetMusic.Size = new System.Drawing.Size(33, 22); + this.btnSetMusic.TabIndex = 8; + this.btnSetMusic.Tag = "0"; + this.btnSetMusic.Text = "M"; + this.btnSetMusic.UseVisualStyleBackColor = true; + this.btnSetMusic.Click += new System.EventHandler(this.btnSetMusic_Click); + // + // lblPM + // + this.lblPM.Location = new System.Drawing.Point(3, 26); + this.lblPM.Name = "lblPM"; + this.lblPM.Size = new System.Drawing.Size(228, 21); + this.lblPM.TabIndex = 7; + this.lblPM.Leave += new System.EventHandler(this.lblName_Leave); + // + // lblName + // + this.lblName.Location = new System.Drawing.Point(3, 1); + this.lblName.Name = "lblName"; + this.lblName.Size = new System.Drawing.Size(263, 21); + this.lblName.TabIndex = 6; + this.lblName.Leave += new System.EventHandler(this.lblName_Leave); + // + // cbRobotMode + // + this.cbRobotMode.AutoSize = true; + this.cbRobotMode.Location = new System.Drawing.Point(3, 54); + this.cbRobotMode.Name = "cbRobotMode"; + this.cbRobotMode.Size = new System.Drawing.Size(136, 19); + this.cbRobotMode.TabIndex = 11; + this.cbRobotMode.Text = "Provisioned Account"; + this.cbRobotMode.UseVisualStyleBackColor = true; + this.cbRobotMode.CheckedChanged += new System.EventHandler(this.cbRobotMode_CheckedChanged); + // + // accountTextBox + // + this.accountTextBox.Location = new System.Drawing.Point(3, 2); + this.accountTextBox.Name = "accountTextBox"; + this.accountTextBox.Size = new System.Drawing.Size(263, 21); + this.accountTextBox.TabIndex = 9; + this.accountTextBox.Text = "example@escargot.chat"; + this.accountTextBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.login_KeyPress); + // + // loginButton + // + this.loginButton.Location = new System.Drawing.Point(145, 50); + this.loginButton.Name = "loginButton"; + this.loginButton.Size = new System.Drawing.Size(121, 22); + this.loginButton.TabIndex = 8; + this.loginButton.Tag = "0"; + this.loginButton.Text = "> Sign in"; + this.loginButton.UseVisualStyleBackColor = true; + this.loginButton.Click += new System.EventHandler(this.loginButton_Click); + // + // passwordTextBox + // + this.passwordTextBox.Location = new System.Drawing.Point(3, 27); + this.passwordTextBox.Name = "passwordTextBox"; + this.passwordTextBox.PasswordChar = '*'; + this.passwordTextBox.Size = new System.Drawing.Size(263, 21); + this.passwordTextBox.TabIndex = 10; + this.passwordTextBox.Text = "sneakysource"; + this.passwordTextBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.login_KeyPress); + // + // tableLayoutPanel7 + // + this.tableLayoutPanel7.ColumnCount = 2; + this.tableLayoutPanel7.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel7.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel7.Controls.Add(this.comboPlaces, 0, 0); + this.tableLayoutPanel7.Controls.Add(this.comboStatus, 0, 0); + this.tableLayoutPanel7.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel7.Location = new System.Drawing.Point(3, 82); + this.tableLayoutPanel7.Name = "tableLayoutPanel7"; + this.tableLayoutPanel7.RowCount = 1; + this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel7.Size = new System.Drawing.Size(269, 29); + this.tableLayoutPanel7.TabIndex = 0; + // + // comboPlaces + // + this.comboPlaces.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboPlaces.DropDownWidth = 220; + this.comboPlaces.FormattingEnabled = true; + this.comboPlaces.Location = new System.Drawing.Point(137, 3); + this.comboPlaces.Name = "comboPlaces"; + this.comboPlaces.Size = new System.Drawing.Size(129, 23); + this.comboPlaces.TabIndex = 6; + this.comboPlaces.Visible = false; + this.comboPlaces.SelectedIndexChanged += new System.EventHandler(this.comboPlaces_SelectedIndexChanged); + // + // comboStatus + // + this.comboStatus.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; + this.comboStatus.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboStatus.FormattingEnabled = true; + this.comboStatus.ItemHeight = 15; + this.comboStatus.Items.AddRange(new object[] { + "Online", + "Busy", + "Away", + "Hidden", + "Offline"}); + this.comboStatus.Location = new System.Drawing.Point(3, 3); + this.comboStatus.Name = "comboStatus"; + this.comboStatus.Size = new System.Drawing.Size(128, 21); + this.comboStatus.TabIndex = 5; + this.comboStatus.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.comboStatus_DrawItem); + this.comboStatus.SelectedIndexChanged += new System.EventHandler(this.comboStatus_SelectedIndexChanged); + this.comboStatus.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.comboStatus_KeyPress); + // + // statusBar + // + this.statusBar.AutoSize = true; + this.statusBar.Dock = System.Windows.Forms.DockStyle.Fill; + this.statusBar.Location = new System.Drawing.Point(3, 604); + this.statusBar.Name = "statusBar"; + this.statusBar.Size = new System.Drawing.Size(637, 30); + this.statusBar.TabIndex = 10; + this.statusBar.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // ClientForm + // + this.AutoScaleBaseSize = new System.Drawing.Size(6, 14); + this.BackColor = System.Drawing.Color.White; + this.ClientSize = new System.Drawing.Size(643, 634); + this.Controls.Add(this.tableLayoutPanel1); + this.Font = new System.Drawing.Font("Arial", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.MinimumSize = new System.Drawing.Size(640, 480); + this.Name = "ClientForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "MSNPSharp Example Client for Escargot"; + this.Load += new System.EventHandler(this.ClientForm_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ClientForm_FormClosing); + this.userMenuStrip.ResumeLayout(false); + this.sortContextMenu.ResumeLayout(false); + this.groupContextMenu.ResumeLayout(false); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.WhatsUpPanel.ResumeLayout(false); + this.WhatsUpPanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pbNewsPicture)).EndInit(); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel2.ResumeLayout(false); + this.splitContainer1.ResumeLayout(false); + this.tableLayoutPanel2.ResumeLayout(false); + this.pnlTreeViewsContainer.ResumeLayout(false); + this.SortPanel.ResumeLayout(false); + this.SortPanel.PerformLayout(); + this.tableLayoutPanel3.ResumeLayout(false); + this.tableLayoutPanel4.ResumeLayout(false); + this.tableLayoutPanel5.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.displayImageBox)).EndInit(); + this.panel1.ResumeLayout(false); + this.tableLayoutPanel6.ResumeLayout(false); + this.pnlLogin.ResumeLayout(false); + this.pnlLogin.PerformLayout(); + this.pnlNameAndPM.ResumeLayout(false); + this.pnlNameAndPM.PerformLayout(); + this.tableLayoutPanel7.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private OpenFileDialog openFileDialog; + private OpenFileDialog openImageDialog; + private System.Windows.Forms.Timer tmrKeepOnLine; + private System.Windows.Forms.Timer tmrNews; + private ImageList ImageList1; + private ContextMenuStrip userMenuStrip; + private ToolStripMenuItem sendIMMenuItem; + private ToolStripMenuItem blockMenuItem; + private ToolStripSeparator toolStripMenuItem2; + private ToolStripMenuItem unblockMenuItem; + private ToolStripMenuItem sendOIMMenuItem; + private ToolStripSeparator toolStripMenuItem3; + private ToolStripMenuItem sendMIMMenuItem; + private ContextMenuStrip sortContextMenu; + private ToolStripMenuItem toolStripSortByStatus; + private ToolStripMenuItem toolStripSortBygroup; + private ToolStripMenuItem toolStripDeleteGroup; + private ContextMenuStrip groupContextMenu; + private ToolStripMenuItem importContactsMenuItem; + private ToolStripMenuItem createCircleMenuItem; + private ToolStripMenuItem deleteMenuItem; + private ToolTip toolTipChangePhoto; + private TableLayoutPanel tableLayoutPanel1; + private Panel WhatsUpPanel; + private LinkLabel lblNewsLink; + private Label lblNews; + private PictureBox pbNewsPicture; + private Button cmdNext; + private Button cmdPrev; + private Label lblWhatsup; + private SplitContainer splitContainer1; + private PropertyGrid propertyGrid; + private TableLayoutPanel tableLayoutPanel2; + private Panel SortPanel; + private TextBox txtSearch; + private Button btnAddNew; + private Button btnSortBy; + private TableLayoutPanel tableLayoutPanel3; + private Panel pnlTreeViewsContainer; + private TreeView treeViewFavoriteList; + private Label statusBar; + private TreeView treeViewFilterList; + private TableLayoutPanel tableLayoutPanel4; + private TableLayoutPanel tableLayoutPanel5; + private Panel panel1; + private TableLayoutPanel tableLayoutPanel6; + private Panel pnlLogin; + private Panel pnlNameAndPM; + private Button btnSetMusic; + private TextBox lblPM; + private TextBox lblName; + private CheckBox cbRobotMode; + private TextBox accountTextBox; + private Button loginButton; + private TextBox passwordTextBox; + private TableLayoutPanel tableLayoutPanel7; + private ComboBox comboPlaces; + private ComboBox comboStatus; + private PictureBox displayImageBox; + + } +} diff --git a/Example/DotMSNClient.cs b/Example/DotMSNClient.cs new file mode 100644 index 0000000..f1299ee --- /dev/null +++ b/Example/DotMSNClient.cs @@ -0,0 +1,2343 @@ +using System; +using System.IO; +using System.Data; +using System.Drawing; +using System.Collections; +using System.Diagnostics; +using System.Windows.Forms; +using System.ComponentModel; +using System.Collections.Generic; +using System.Threading; +using System.Xml; + +namespace MSNPSharpClient +{ + using MSNPSharp; + using MSNPSharp.Core; + using MSNPSharp.DataTransfer; + using MSNPSharp.MSNWS.MSNABSharingService; + using MSNPSharp.Utilities; + + /// + /// MSNPSharp Client example. + /// + public partial class ClientForm : System.Windows.Forms.Form + { + // Create a Messenger object to use MSNPSharp. + private Messenger messenger = new Messenger(); + private List convforms = new List(0); + private TraceForm traceform = new TraceForm(); + + public List ConversationForms + { + get + { + return convforms; + } + } + + public Messenger Messenger + { + get + { + return messenger; + } + } + + public ClientForm() + { + // + // Required for Windows Form Designer support + // + InitializeComponent(); + + this.Icon = Properties.Resources.MSNPSharp_logo_small_ico; + + // You can set proxy settings here + // for example: messenger.ConnectivitySettings.ProxyHost = "10.0.0.2"; + + Settings.TraceSwitch.Level = System.Diagnostics.TraceLevel.Verbose; + + //Set the p2p invitation interval in the whole invitation request queue (in ms) + Schedulers.P2PInvitationScheduler.DelayTime = 5000; + Schedulers.SwitchBoardRequestScheduler.DelayTime = 1000; + + if (Settings.IsMono) //I am running on Mono. + { + // Don't enable this on mono, because mono raises NotImplementedException. + Settings.EnableGzipCompressionForWebServices = false; + } + +#if DEBUG + + //How to save your personal addressbook. + //If you want your addressbook have a better reading/writting performance, use MclSerialization.None + //In this case, your addressbook will be save as a xml file, everyone can read it. + //If you want your addressbook has a smaller size, use MclSerialization.Compression. + //In this case, your addressbook file will be save in gzip format, none can read it, but the performance is not so good. + Settings.SerializationType = MSNPSharp.IO.MclSerialization.None; +#elif TRACE + Settings.SerializationType = MSNPSharp.IO.MclSerialization.Compression | MSNPSharp.IO.MclSerialization.Cryptography; +#endif + + // The following line is very IMPOTANT. + // Keep the messenger sending PNG to the server in a proper frequency, or it will be kicked offline. + this.tmrKeepOnLine.Tick += new EventHandler(tmrKeepOnLine_Tick); + + // If you want to use it in an environment that does not have write permission, set NoSave to true. + //Settings.NoSave = true; + + // set the events that we will handle + // remember that the nameserver is the server that sends contact lists, notifies you of contact status changes, etc. + // a switchboard server handles the individual conversation sessions. + messenger.NameserverProcessor.ConnectionEstablished += new EventHandler(NameserverProcessor_ConnectionEstablished); + messenger.Nameserver.SignedIn += new EventHandler(Nameserver_SignedIn); + messenger.Nameserver.SignedOff += new EventHandler(Nameserver_SignedOff); + messenger.NameserverProcessor.ConnectingException += new EventHandler(NameserverProcessor_ConnectingException); + messenger.Nameserver.ExceptionOccurred += new EventHandler(Nameserver_ExceptionOccurred); + messenger.Nameserver.AuthenticationError += new EventHandler(Nameserver_AuthenticationError); + messenger.Nameserver.ServerErrorReceived += new EventHandler(Nameserver_ServerErrorReceived); + + // Receive messages send by MSN contacts. + messenger.MessageManager.MessageArrived += new EventHandler(MessageManager_MessageArrived); + + // Listen for the data transfer events (i.e. file transfer invitation, activity invitation) + messenger.TransferInvitationReceived += new EventHandler(messenger_TransferInvitationReceived); + + // Listen to ping answer event. In each ping answer, MSN will give you a number. That is the interval to send the next Ping. + // You can send a Ping by using Messenger.Nameserver.SendPing(). + messenger.Nameserver.PingAnswer += new EventHandler(Nameserver_PingAnswer); + + messenger.Nameserver.OwnerVerified += new EventHandler(Nameserver_OwnerVerified); + messenger.Nameserver.ContactOnline += new EventHandler(Nameserver_ContactOnline); + messenger.Nameserver.ContactOffline += new EventHandler(Nameserver_ContactOffline); + + + // SynchronizationCompleted will fired after the updated operation for your contact list has completed. + messenger.ContactService.SynchronizationCompleted += new EventHandler(ContactService_SynchronizationCompleted); + // ReverseAdded will fired after a contact adds you to his/her contact list. + messenger.ContactService.ReverseAdded += new EventHandler(Nameserver_ReverseAdded); + + messenger.ContactService.ReverseRemoved += new EventHandler(ContactService_ReverseRemoved); + // ContactAdded will fired after a contact added to any role list. + messenger.ContactService.ContactAdded += new EventHandler(ContactService_ContactAdded); + // ContactRemoved will fired after a contact removed from any role list. + messenger.ContactService.ContactRemoved += new EventHandler(ContactService_ContactRemoved); + + #region Circle events + + // These are circle events. They will be fired after corresponding circle operation completed. + messenger.ContactService.CreateCircleCompleted += new EventHandler(ContactService_CircleCreated); + messenger.ContactService.JoinedCircleCompleted += new EventHandler(ContactService_JoinedCircle); + messenger.ContactService.JoinCircleInvitationReceived += new EventHandler(ContactService_JoinCircleInvitationReceived); + messenger.ContactService.ExitCircleCompleted += new EventHandler(ContactService_ExitCircle); + messenger.ContactService.CircleMemberJoined += new EventHandler(ContactService_CircleMemberJoined); + messenger.ContactService.CircleMemberLeft += new EventHandler(ContactService_CircleMemberLeft); + messenger.Nameserver.CircleOnline += new EventHandler(Nameserver_CircleOnline); + messenger.Nameserver.CircleOffline += new EventHandler(Nameserver_CircleOffline); + messenger.Nameserver.CircleMemberOnline += new EventHandler(Nameserver_CircleMemberOnline); + messenger.Nameserver.CircleMemberOffline += new EventHandler(Nameserver_CircleMemberOffline); + messenger.Nameserver.LeftCircleConversation += new EventHandler(Nameserver_CircleMemberLeftConversation); + messenger.Nameserver.JoinedCircleConversation += new EventHandler(Nameserver_CircleMemberJoinedConversation); + messenger.Nameserver.CircleTextMessageReceived += new EventHandler(Nameserver_CircleTextMessageReceived); + messenger.Nameserver.CircleNudgeReceived += new EventHandler(Nameserver_CircleNudgeReceived); + + #endregion + + + #region Offline Message Operation events + + // OIMReceived will be triggered after receved an Offline Message. + messenger.OIMService.OIMReceived += new EventHandler(Nameserver_OIMReceived); + + // Triggered after the send operation for an Offline Message has been completed. + // If the operation failed, there will contains an error in the event args. + messenger.OIMService.OIMSendCompleted += new EventHandler(OIMService_OIMSendCompleted); + + #endregion + + + messenger.WhatsUpService.GetWhatsUpCompleted += new EventHandler(WhatsUpService_GetWhatsUpCompleted); + + #region Webservice Error handler + + // Handle Service Operation Errors + //In most cases, these error are not so important. + messenger.ContactService.ServiceOperationFailed += new EventHandler(ServiceOperationFailed); + messenger.OIMService.ServiceOperationFailed += new EventHandler(ServiceOperationFailed); + messenger.StorageService.ServiceOperationFailed += new EventHandler(ServiceOperationFailed); + messenger.WhatsUpService.ServiceOperationFailed += new EventHandler(ServiceOperationFailed); + + #endregion + } + + public static class ImageIndexes + { + public const int Closed = 0; + public const int Open = 1; + public const int Circle = 2; + + public const int Online = 3; + public const int Busy = 4; + public const int Away = 5; + public const int Idle = 6; + public const int Hidden = 7; + public const int Offline = 8; + + // Show always (0/0) + public const string FavoritesNodeKey = "__10F"; + public const string CircleNodeKey = "__20C"; + // Sort by status (0) + public const string MobileNodeKey = "__30M"; + public const string OnlineNodeKey = "__32N"; + public const string OfflineNodeKey = "__34F"; + // Sort by categories (0/0) + public const string NoGroupNodeKey = "ZZZZZ"; + + public static int GetStatusIndex(PresenceStatus status) + { + switch (status) + { + case PresenceStatus.Online: + return Online; + + case PresenceStatus.Busy: + case PresenceStatus.Phone: + return Busy; + + case PresenceStatus.BRB: + case PresenceStatus.Away: + case PresenceStatus.Lunch: + return Away; + + case PresenceStatus.Idle: + return Idle; + case PresenceStatus.Hidden: + return Hidden; + + case PresenceStatus.Offline: + return Offline; + + default: + return Offline; + } + } + } + + private void ClientForm_Load(object sender, EventArgs e) + { + ImageList1.Images.Add(MSNPSharpClient.Properties.Resources.closed); + ImageList1.Images.Add(MSNPSharpClient.Properties.Resources.open); + ImageList1.Images.Add(MSNPSharpClient.Properties.Resources.circle); + + ImageList1.Images.Add(MSNPSharpClient.Properties.Resources.online); + ImageList1.Images.Add(MSNPSharpClient.Properties.Resources.busy); + ImageList1.Images.Add(MSNPSharpClient.Properties.Resources.away); + ImageList1.Images.Add(MSNPSharpClient.Properties.Resources.idle); + ImageList1.Images.Add(MSNPSharpClient.Properties.Resources.hidden); + ImageList1.Images.Add(MSNPSharpClient.Properties.Resources.offline); + + Version dllVersion = messenger.GetType().Assembly.GetName().Version; + Text += " (v" + dllVersion.Major + "." + dllVersion.Minor + "." + dllVersion.Build + " r" + dllVersion.Revision + ")"; + treeViewFavoriteList.TreeViewNodeSorter = StatusSorter.Default; + + comboStatus.SelectedIndex = 0; + + if (toolStripSortByStatus.Checked) + SortByStatus(null); + else + SortByGroup(null); + + // ******* Listen traces ***** + traceform.Show(); + } + + + private void ClientForm_FormClosing(object sender, FormClosingEventArgs e) + { + if (Messenger.Connected) + { + Messenger.Nameserver.SignedOff -= Nameserver_SignedOff; + + ResetAll(); + Messenger.Disconnect(); + } + + traceform.Close(); + } + + void Nameserver_CircleMemberOffline(object sender, CircleMemberEventArgs e) + { + RefreshCircleList(sender, e); + } + + void Nameserver_CircleMemberOnline(object sender, CircleMemberEventArgs e) + { + RefreshCircleList(sender, e); + } + + void Nameserver_CircleNudgeReceived(object sender, CircleMemberEventArgs e) + { + Trace.WriteLine("Circle " + e.Circle.ToString() + ": Member: " + e.Member.ToString() + " send you a nudge."); + AutoGroupMessageReply(e.Circle); + } + + private void AutoGroupMessageReply(Circle circle) + { + if (Messenger.ContactList.Owner.Status != PresenceStatus.Hidden || Messenger.ContactList.Owner.Status != PresenceStatus.Offline) + circle.SendMessage(new TextMessage("MSNPSharp example client auto reply.")); + } + + void Nameserver_CircleTextMessageReceived(object sender, CircleTextMessageEventArgs e) + { + Trace.WriteLine("Circle " + e.Sender.ToString() + ": Member: " + e.TriggerMember.ToString() + " send you a message :" + e.Message.ToString()); + AutoGroupMessageReply(e.Sender); + } + + void Nameserver_CircleMemberJoinedConversation(object sender, CircleMemberEventArgs e) + { + Trace.WriteLine("Circle member " + e.Member.ToString() + " joined the circle conversation: " + e.Circle.ToString()); + } + + void Nameserver_CircleMemberLeftConversation(object sender, CircleMemberEventArgs e) + { + Trace.WriteLine("Circle member " + e.Member.ToString() + " has left the circle: " + e.Circle.ToString()); + } + + void Nameserver_CircleOnline(object sender, CircleEventArgs e) + { + Trace.WriteLine("Circle go online: " + e.Circle.ToString()); + RefreshCircleList(sender, e); + } + + void Nameserver_CircleOffline(object sender, CircleEventArgs e) + { + Trace.WriteLine("Circle go offline: " + e.Circle.ToString()); + RefreshCircleList(sender, e); + } + + void ContactService_ExitCircle(object sender, CircleEventArgs e) + { + RefreshCircleList(sender, e); + } + + void ContactService_JoinedCircle(object sender, CircleEventArgs e) + { + RefreshCircleList(sender, e); + messenger.ContactService.ExitCircle(e.Circle); //Demostrate how to leave a circle. + } + + + void ContactService_CircleMemberLeft(object sender, CircleMemberEventArgs e) + { + RefreshCircleList(sender, null); + } + + void ContactService_CircleMemberJoined(object sender, CircleMemberEventArgs e) + { + RefreshCircleList(sender, null); + } + + void ContactService_JoinCircleInvitationReceived(object sender, CircleEventArgs e) + { + messenger.ContactService.AcceptCircleInvitation(e.Circle); + } + + void ContactService_CircleCreated(object sender, CircleEventArgs e) + { + RefreshCircleList(sender, e); + } + + void RefreshCircleList(object sender, EventArgs e) + { + if (InvokeRequired) + { + BeginInvoke(new EventHandler(RefreshCircleList), new object[] { sender, e }); + return; + } + + Contact circle = null; + + if (e is CircleMemberEventArgs) + circle = (e as CircleMemberEventArgs).Circle; + else if (e is CircleEventArgs) + circle = (e as CircleEventArgs).Circle; + + if (toolStripSortByStatus.Checked) + { + SortByStatus(circle); + } + else + { + SortByGroup(circle); + } + } + + void ServiceOperationFailed(object sender, ServiceOperationFailedEventArgs e) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, e.Method + ": " + e.Exception.ToString(), sender.GetType().Name); + } + + void ContactService_SynchronizationCompleted(object sender, EventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(ContactService_SynchronizationCompleted), sender, e); + return; + } + + lblNews.Text = "Getting your friends' news..."; + messenger.WhatsUpService.GetWhatsUp(200); + } + + List activities = new List(); + void WhatsUpService_GetWhatsUpCompleted(object sender, GetWhatsUpCompletedEventArgs e) + { + if (InvokeRequired) + { + BeginInvoke(new EventHandler(WhatsUpService_GetWhatsUpCompleted), new object[] { sender, e }); + return; + } + + if (e.Error != null) + { + lblNews.Text = "ERROR: " + e.Error.ToString(); + } + else + { + activities.Clear(); + + foreach (ActivityDetailsType activityDetails in e.Response.Activities) + { + // Show status news + if (activityDetails.ApplicationId == "6262816084389410") + { + activities.Add(activityDetails); + } + + Contact c = messenger.ContactList.GetContactByCID(long.Parse(activityDetails.OwnerCID)); + + if (c != null) + { + c.Activities.Add(activityDetails); + } + } + + if (activities.Count == 0) + { + lblNews.Text = "No news"; + return; + } + + lblNewsLink.Text = "Get Feeds"; + lblNewsLink.Tag = e.Response.FeedUrl; + tmrNews.Enabled = true; + } + } + + private int currentActivity = 0; + private bool activityForward = true; + private void tmrNews_Tick(object sender, EventArgs e) + { + if (currentActivity >= activities.Count || currentActivity < 0) + { + currentActivity = 0; + } + + ActivityDetailsType activitiy = activities[currentActivity]; + if (activitiy.ApplicationId == "6262816084389410") + { + string name = string.Empty; + string status = string.Empty; + + foreach (TemplateVariableBaseType t in activitiy.TemplateVariables) + { + if (t is PublisherIdTemplateVariable) + { + name = ((PublisherIdTemplateVariable)t).NameHint; + } + else if (t is TextTemplateVariable) + { + status = ((TextTemplateVariable)t).Value; + } + } + + lblNews.Text = name + ": " + status; + + Contact c = messenger.ContactList.GetContactByCID(long.Parse(activitiy.OwnerCID)); + + if (c != null) + { + if (c.DisplayImage != null && c.DisplayImage.Image != null) + { + pbNewsPicture.Image = c.DisplayImage.Image; + } + else if (c.UserTileURL != null) + { + pbNewsPicture.LoadAsync(c.UserTileURL.AbsoluteUri); + } + else + { + pbNewsPicture.Image = null; + } + } + } + if (activityForward) + currentActivity++; + else + currentActivity--; + } + + private void cmdPrev_Click(object sender, EventArgs e) + { + if (activities.Count > 0) + { + activityForward = false; + + if (currentActivity > 0) + currentActivity--; + else + currentActivity = activities.Count - 1; + + if (tmrNews.Enabled) + tmrNews_Tick(this, EventArgs.Empty); + } + } + + private void cmdNext_Click(object sender, EventArgs e) + { + if (activities.Count > 0) + { + activityForward = true; + + if (currentActivity < activities.Count) + currentActivity++; + + if (tmrNews.Enabled) + tmrNews_Tick(this, EventArgs.Empty); + } + } + + private void lblNewsLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + if (lblNewsLink.Tag != null) + { + Process.Start(lblNewsLink.Tag.ToString()); + } + } + + void Owner_PersonalMessageChanged(object sender, EventArgs e) + { + if (InvokeRequired) + { + BeginInvoke(new EventHandler(Owner_PersonalMessageChanged), new object[] { sender, e }); + return; + } + + lblName.Text = Messenger.ContactList.Owner.Name; + + if (Messenger.ContactList.Owner.PersonalMessage != null && Messenger.ContactList.Owner.PersonalMessage.Message != null) + { + lblPM.Text = System.Web.HttpUtility.HtmlDecode(Messenger.ContactList.Owner.PersonalMessage.Message); + } + } + + void Owner_DisplayImageChanged(object sender, DisplayImageChangedEventArgs e) + { + if (InvokeRequired) + { + displayImageBox.BeginInvoke(new EventHandler(Owner_DisplayImageChanged), new object[] { sender, e }); + return; + } + + displayImageBox.Image = e.NewDisplayImage.Image; + } + + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new ClientForm()); + } + + void Nameserver_OwnerVerified(object sender, EventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(Nameserver_OwnerVerified), sender, e); + return; + } + + Messenger.ContactList.Owner.DisplayImageChanged += new EventHandler(Owner_DisplayImageChanged); + Messenger.ContactList.Owner.PersonalMessageChanged += new EventHandler(Owner_PersonalMessageChanged); + Messenger.ContactList.Owner.ScreenNameChanged += new EventHandler(Owner_PersonalMessageChanged); + Messenger.ContactList.Owner.PlacesChanged += new EventHandler(Owner_PlacesChanged); + Messenger.ContactList.Owner.StatusChanged += new EventHandler(Owner_StatusChanged); + } + + void Nameserver_ContactOnline(object sender, ContactEventArgs e) + { + BeginInvoke(new EventHandler(ContactOnlineOffline), new object[] { sender, e }); + } + + void Nameserver_ContactOffline(object sender, ContactEventArgs e) + { + Invoke(new EventHandler(ContactOnlineOffline), new object[] { sender, e }); + } + + void ContactOnlineOffline(object sender, ContactEventArgs e) + { + if (toolStripSortByStatus.Checked) + SortByStatus(e.Contact); + else + SortByGroup(e.Contact); + } + + void Nameserver_PingAnswer(object sender, PingAnswerEventArgs e) + { + nextPing = e.SecondsToWait; + } + + void Nameserver_OIMReceived(object sender, OIMReceivedEventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(Nameserver_OIMReceived), sender, e); + return; + } + + if (DialogResult.Yes == MessageBox.Show( + "OIM received at : " + e.ReceivedTime + "\r\nFrom : " + e.NickName + " (" + e.Email + ") " + ":\r\n" + + e.Message + "\r\n\r\n\r\nClick yes, if you want to receive this message next time you login.", + "Offline Message from " + e.Email, MessageBoxButtons.YesNoCancel)) + { + e.IsRead = false; + } + } + + + void MessageManager_MessageArrived(object sender, MessageArrivedEventArgs e) + { + if (InvokeRequired) + { + BeginInvoke(new EventHandler(MessageManager_MessageArrived), new object[] { sender, e }); + return; + } + else + { + foreach (ConversationForm cform in ConversationForms) + { + if (cform.ConversationID == e.ConversationID) + { + //TODO: print message on the form. + cform.OnMessageReceived(sender, e); + return; + } + } + + CreateConversationForm(e.Sender, e.ConversationID).OnMessageReceived(sender, e); + } + } + + void OIMService_OIMSendCompleted(object sender, OIMSendCompletedEventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(OIMService_OIMSendCompleted), sender, e); + return; + } + + if (e.Error != null) + { + MessageBox.Show(e.Error.Message, "OIM Send Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + void ContactService_ContactRemoved(object sender, ListMutateEventArgs e) + { + Trace.WriteLine(e.Contact.Hash + " removed from the " + e.AffectedList + " role list."); + } + + void ContactService_ContactAdded(object sender, ListMutateEventArgs e) + { + if (Messenger.Nameserver.IsSignedIn) + { + e.Contact.OnForwardList = true; + e.Contact.OnAllowedList = true; + } + Trace.WriteLine(e.Contact.Hash + " added to the " + e.AffectedList + " role list."); + + } + + void ContactService_ReverseRemoved(object sender, ContactEventArgs e) + { + Trace.WriteLine(e.Contact.Hash + " removed you their contact (forward) list."); + } + + void Nameserver_ReverseAdded(object sender, ContactEventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(Nameserver_ReverseAdded), sender, e); + return; + } + + Contact contact = e.Contact; + if (messenger.ContactList.Owner.NotifyPrivacy == NotifyPrivacy.PromptOnAdd + /* || messenger.Nameserver.BotMode */) //If you want your provisioned account in botmode to fire ReverseAdded event, uncomment this. + { + // Show pending window if it is necessary. + if (contact.OnPendingList || + (contact.OnReverseList && !contact.OnAllowedList && !contact.OnBlockedList)) + { + ReverseAddedForm form = new ReverseAddedForm(contact); + form.FormClosed += delegate(object f, FormClosedEventArgs fce) + { + form = f as ReverseAddedForm; + if (DialogResult.OK == form.DialogResult) + { + if (form.AddToContactList) + { + messenger.ContactService.AddNewContact(contact.Mail); + System.Threading.Thread.Sleep(200); + + if (form.Blocked) + { + contact.Blocked = true; + } + } + else if (form.Blocked) + { + contact.Blocked = true; + } + else + { + contact.OnAllowedList = true; + } + + System.Threading.Thread.Sleep(200); + contact.OnPendingList = false; + } + return; + }; + form.Show(this); + } + else + { + MessageBox.Show(contact.Mail + " accepted your invitation and added you their contact list."); + } + } + } + + + /// + /// A delegate passed to Invoke in order to create the conversation form in the thread of the main form. + /// + private delegate void SetStatusDelegate(string status); + + private void SetStatusSynchronized(string status) + { + statusBar.Text = status; + } + + private void SetStatus(string status) + { + if (InvokeRequired) + { + this.Invoke(new SetStatusDelegate(SetStatusSynchronized), new object[] { status }); + } + else + { + SetStatusSynchronized(status); + } + } + + /// + /// Sign into the messenger network. Disconnect first if a connection has already been established. + /// + /// + /// + private void loginButton_Click(object sender, System.EventArgs e) + { + switch (Convert.ToInt32(loginButton.Tag)) + { + case 0: // not connected -> connect + { + if (messenger.Connected) + { + SetStatus("Disconnecting from server"); + messenger.Disconnect(); + } + + // set the credentials, this is ofcourse something every MSNPSharp program will need to implement. + messenger.Credentials = new Credentials(accountTextBox.Text, passwordTextBox.Text, MsnProtocol.MSNP18); + + // inform the user what is happening and try to connecto to the messenger network. + SetStatus("Connecting to server"); + messenger.Connect(); + + displayImageBox.Image = global::MSNPSharpClient.Properties.Resources.loading; + + loginButton.Tag = 1; + loginButton.Text = "Cancel"; + initialExpand = true; + + // note that Messenger.Connect() will run in a seperate thread and return immediately. + // it will fire events that informs you about the status of the connection attempt. + // these events are registered in the constructor. + + } + break; + + case 1: // connecting -> cancel + { + if (messenger.Connected) + messenger.Disconnect(); + + if (toolStripSortByStatus.Checked) + SortByStatus(null); + else + SortByGroup(null); + + displayImageBox.Image = null; + loginButton.Tag = 0; + loginButton.Text = "> Sign in"; + pnlNameAndPM.Visible = false; + comboPlaces.Visible = false; + initialExpand = true; + + } + break; + + case 2: // connected -> disconnect + { + if (messenger.Connected) + messenger.Disconnect(); + + if (toolStripSortByStatus.Checked) + SortByStatus(null); + else + SortByGroup(null); + + displayImageBox.Image = null; + loginButton.Tag = 0; + loginButton.Text = "> Sign in"; + pnlNameAndPM.Visible = true; + comboPlaces.Visible = true; + initialExpand = true; + + } + break; + } + } + + private void login_KeyPress(object sender, KeyPressEventArgs e) + { + if ((e.KeyChar == '\r') || (e.KeyChar == '\r')) + { + loginButton.PerformClick(); + } + } + + void Owner_StatusChanged(object sender, StatusChangedEventArgs e) + { + if (InvokeRequired) + { + BeginInvoke(new EventHandler(Owner_StatusChanged), new object[] { sender, e }); + return; + } + + if (messenger.Nameserver.IsSignedIn) + { + comboStatus.SelectedIndex = comboStatus.FindString(GetStatusString(Messenger.ContactList.Owner.Status)); + } + } + + private string GetStatusString(PresenceStatus status) + { + switch (status) + { + case PresenceStatus.Away: + case PresenceStatus.BRB: + case PresenceStatus.Lunch: + case PresenceStatus.Idle: + return "Away"; + case PresenceStatus.Online: + return "Online"; + case PresenceStatus.Offline: + return "Offline"; + case PresenceStatus.Hidden: + return "Hidden"; + case PresenceStatus.Busy: + case PresenceStatus.Phone: + return "Busy"; + + } + + return "Offline"; + } + + private void comboStatus_SelectedIndexChanged(object sender, EventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(comboStatus_SelectedIndexChanged), sender, e); + return; + } + + PresenceStatus newstatus = (PresenceStatus)Enum.Parse(typeof(PresenceStatus), comboStatus.Text); + + if (messenger.Connected) + { + if (newstatus == PresenceStatus.Offline) + { + PresenceStatus old = Messenger.ContactList.Owner.Status; + + foreach (ConversationForm convform in ConversationForms) + { + if (convform.Visible == true) + { + if (MessageBox.Show("You are signing out from example client. All windows will be closed.", "Sign out", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) + { + return; + } + else + { + break; + } + } + } + + Messenger.Disconnect(); + comboStatus.SelectedIndex = 0; + } + else + { + Messenger.ContactList.Owner.Status = newstatus; + } + } + else if (newstatus == PresenceStatus.Offline) + { + comboStatus.SelectedIndex = 0; + } + } + + private void comboStatus_DrawItem(object sender, DrawItemEventArgs e) + { + if (e.Index == -1) + return; + + e.Graphics.FillRectangle(Brushes.White, e.Bounds); + if ((e.State & DrawItemState.Selected) != DrawItemState.None) + e.DrawBackground(); + + PresenceStatus newstatus = (PresenceStatus)Enum.Parse(typeof(PresenceStatus), comboStatus.Items[e.Index].ToString()); + Brush brush = Brushes.Green; + + switch (newstatus) + { + case PresenceStatus.Online: + brush = Brushes.Green; + break; + + case PresenceStatus.Busy: + brush = Brushes.Red; + break; + + case PresenceStatus.Away: + brush = Brushes.Orange; + break; + + case PresenceStatus.Hidden: + brush = Brushes.Gray; + break; + + case PresenceStatus.Offline: + brush = Brushes.Black; + break; + } + + Point imageLocation = new Point(e.Bounds.X + 2, e.Bounds.Y + 2); + e.Graphics.FillRectangle(brush, new Rectangle(imageLocation, new Size(12, 12))); + + PointF textLocation = new PointF(imageLocation.X + 16, imageLocation.Y); + e.Graphics.DrawString(newstatus.ToString(), PARENT_NODE_FONT, Brushes.Black, textLocation); + } + + private void comboPlaces_SelectedIndexChanged(object sender, EventArgs e) + { + if (comboPlaces.SelectedIndex > 0) + { + string place = comboPlaces.Text.Split(' ')[comboPlaces.Text.Split(' ').Length - 1]; + if (comboPlaces.SelectedIndex == 1) + { + Messenger.ContactList.Owner.Status = PresenceStatus.Offline; + comboPlaces.Visible = false; + } + else if (comboPlaces.SelectedIndex >= 1) + { + Guid placeId = places[comboPlaces.SelectedIndex - 2]; + if (placeId == Guid.Empty) + { + comboPlaces.Visible = false; + Messenger.ContactList.Owner.SignoutFromEverywhere(); + } + else + { + Messenger.ContactList.Owner.SignoutFrom(placeId); //places does not contain the current places. + } + } + } + } + + void cbRobotMode_CheckedChanged(object sender, EventArgs e) + { + ComboBox cbBotMode = sender as ComboBox; + messenger.Nameserver.BotMode = cbRobotMode.Checked; + } + + List places = new List(0); + + private void Owner_PlacesChanged(object sender, EventArgs e) + { + if (comboPlaces.InvokeRequired) + { + comboPlaces.BeginInvoke(new EventHandler(Owner_PlacesChanged), new object[] { sender, e }); + return; + } + + // if (Messenger.ContactList.Owner.Places.Count > 1) + { + comboPlaces.BeginUpdate(); + comboPlaces.Items.Clear(); + comboPlaces.Items.Add("(" + Messenger.ContactList.Owner.PlaceCount + ") Places"); + comboPlaces.Items.Add("Signout from here (" + Messenger.ContactList.Owner.EpName + ")"); + + foreach (KeyValuePair keyvalue in Messenger.ContactList.Owner.EndPointData) + { + if (keyvalue.Key != NSMessageHandler.MachineGuid) + { + comboPlaces.Items.Add("Signout from " + (keyvalue.Value as PrivateEndPointData).Name); + places.Add(keyvalue.Key); + } + } + + comboPlaces.SelectedIndex = 0; + comboPlaces.Visible = true; + comboPlaces.EndUpdate(); + } + } + + private void NameserverProcessor_ConnectionEstablished(object sender, EventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(NameserverProcessor_ConnectionEstablished), sender, e); + return; + } + + messenger.Nameserver.AutoSynchronize = !cbRobotMode.Checked; + + SetStatus("Connected to server"); + } + + private void Nameserver_SignedIn(object sender, EventArgs e) + { + + if (InvokeRequired) + { + BeginInvoke(new EventHandler(Nameserver_SignedIn), sender, e); + return; + } + + SetStatus("Signed into the messenger network as " + Messenger.ContactList.Owner.Name); + + // set our presence status + loginButton.Tag = 2; + loginButton.Text = "Sign off"; + pnlNameAndPM.Visible = true; + comboPlaces.Visible = true; + + Messenger.ContactList.Owner.Status = (PresenceStatus)Enum.Parse(typeof(PresenceStatus), comboStatus.Text); + + propertyGrid.SelectedObject = Messenger.ContactList.Owner; + displayImageBox.Image = Messenger.ContactList.Owner.DisplayImage.Image; + displayImageBox.SizeMode = PictureBoxSizeMode.Zoom; + + UpdateContactlist(sender, e); + } + + private void Nameserver_SignedOff(object sender, SignedOffEventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(Nameserver_SignedOff), sender, e); + return; + } + + SetStatus("Signed off from the messenger network"); + ResetAll(); + } + + private void ResetAll() + { + tmrKeepOnLine.Enabled = false; + tmrNews.Enabled = false; + + displayImageBox.Image = null; + displayImageBox.SizeMode = PictureBoxSizeMode.CenterImage; + + loginButton.Tag = 0; + loginButton.Text = "> Sign in"; + pnlNameAndPM.Visible = false; + comboPlaces.Visible = false; + propertyGrid.SelectedObject = null; + + treeViewFavoriteList.Nodes.Clear(); + treeViewFilterList.Nodes.Clear(); + + if (toolStripSortByStatus.Checked) + SortByStatus(null); + else + SortByGroup(null); + + places.Clear(); + + List convFormsClone = new List(ConversationForms); + foreach(ConversationForm convForm in convFormsClone) + { + convForm.Close(); + } + } + + private void Nameserver_ExceptionOccurred(object sender, ExceptionEventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(Nameserver_ExceptionOccurred), new object[] { sender, e }); + } + else + { + + // ignore the unauthorized exception, since we're handling that error in another method. + if (e.Exception is UnauthorizedException) + return; + + MessageBox.Show(e.Exception.ToString(), "Nameserver exception"); + } + } + + private void NameserverProcessor_ConnectingException(object sender, ExceptionEventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(Nameserver_ExceptionOccurred), new object[] { sender, e }); + } + else + { + MessageBox.Show(e.Exception.ToString(), "Connecting exception"); + SetStatus("Connecting failed"); + } + } + + private void Nameserver_AuthenticationError(object sender, ExceptionEventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(Nameserver_ExceptionOccurred), new object[] { sender, e }); + } + else + { + MessageBox.Show("Authentication failed, check your account or password.\r\n Error detail:\r\n " + e.Exception.InnerException.Message + "\r\n" + + " StackTrace:\r\n " + e.Exception.InnerException.StackTrace + , "Authentication Error"); + SetStatus("Authentication failed"); + } + } + + /// + /// Updates the treeView. + /// + private void UpdateContactlist(object sender, EventArgs e) + { + if (messenger.Connected == false) + return; + + if (toolStripSortByStatus.Checked) + SortByStatus(null); + else + SortByGroup(null); + + tmrKeepOnLine.Enabled = true; + } + + + /// + /// Notifies the user of errors which are send by the MSN server. + /// + /// + /// + private void Nameserver_ServerErrorReceived(object sender, MSNErrorEventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(Nameserver_ServerErrorReceived), new object[] { sender, e }); + } + else + { + // when the MSN server sends an error code we want to be notified. + MessageBox.Show(e.MSNError.ToString(), "Server error received"); + SetStatus("Server error received"); + } + } + + /// + /// A delegate passed to Invoke in order to create the conversation form in the thread of the main form. + /// + private delegate ConversationForm CreateConversationDelegate(Contact remote, ConversationID cid); + + private ConversationForm CreateConversationForm(Contact remote, ConversationID cid) + { + + // create a new conversation. However do not show the window untill a message is received. + // for example, a conversation will be created when the remote client sends wants to send + // you a file. You don't want to show the conversation form in that case. + ConversationForm conversationForm = new ConversationForm(Messenger, remote, cid); + // do this to create the window handle. Otherwise we are not able to call Invoke() on the + // conversation form later. + conversationForm.Handle.ToInt32(); + ConversationForms.Add(conversationForm); + + conversationForm.FormClosing += delegate + { + ConversationForms.Remove(conversationForm); + }; + + return conversationForm; + } + + + /// + /// Asks the user to accept or deny the incoming filetransfer invitation. + /// + /// + /// + private void messenger_TransferInvitationReceived(object sender, MSNSLPInvitationEventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(messenger_TransferInvitationReceived), sender, e); + return; + } + + if (e.TransferProperties.DataType == DataTransferType.File) + { + e.DelayProcess = true; + + FileTransferForm ftf = new FileTransferForm(e); + ftf.Show(this); + + } + else if (e.TransferProperties.DataType == DataTransferType.Activity) + { + if (MessageBox.Show( + e.TransferProperties.RemoteContact.Name + + " wants to invite you to join an activity.\r\nActivity name: " + + e.Activity.ActivityName + "\r\nAppID: " + e.Activity.AppID, + "Activity invitation", + MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) + { + e.TransferSession.DataStream = new MemoryStream(); + e.Accept = true; + e.TransferSession.AutoCloseStream = true; + } + } + } + + private int nextPing = 50; + private void tmrKeepOnLine_Tick(object sender, EventArgs e) + { + if (nextPing > 0) + nextPing--; + if (nextPing == 0) + { + nextPing--; + messenger.Nameserver.SendPing(); + } + } + + + + private static Font PARENT_NODE_FONT = new Font("Tahoma", 8f, FontStyle.Bold); + private static Font PARENT_NODE_FONT_BANNED = new Font("Tahoma", 8f, FontStyle.Bold | FontStyle.Strikeout); + private static Font USER_NODE_FONT = new Font("Tahoma", 8f); + private static Font USER_NODE_FONT_BANNED = new Font("Tahoma", 8f, FontStyle.Strikeout); + public class StatusSorter : IComparer + { + public static StatusSorter Default = new StatusSorter(); + private StatusSorter() + { + } + public int Compare(object x, object y) + { + TreeNode node = x as TreeNode; + TreeNode node2 = y as TreeNode; + + if (node.Tag is string && node2.Tag is string) + { + // Online (0), Offline (1) + return node.Tag.ToString().CompareTo(node2.Tag.ToString()); + } + else if (node.Tag is Circle && node2.Tag is Circle) + { + + return ((Circle)node.Tag).AddressBookId.CompareTo(((Circle)node2.Tag).AddressBookId); + + } + else if (node.Tag is Contact && node2.Tag is Contact) + { + if (((Contact)node.Tag).Online == ((Contact)node2.Tag).Online) + { + return string.Compare(((Contact)node.Tag).Name, ((Contact)node2.Tag).Name, StringComparison.CurrentCultureIgnoreCase); + } + if (((Contact)node.Tag).Online) + return -1; + else if (((Contact)node2.Tag).Online) + return 1; + } + else if (node.Tag is ContactGroup && node2.Tag is ContactGroup) + { + return string.Compare(((ContactGroup)node.Tag).Name, ((ContactGroup)node2.Tag).Name, StringComparison.CurrentCultureIgnoreCase); + } + return 0; + } + } + + private void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) + { + if ((e.Button == MouseButtons.Left) && (e.Node.Level != 0)) + { + Contact selectedContact = treeViewFavoriteList.SelectedNode.Tag as Contact; + + if (selectedContact != null) + { + propertyGrid.SelectedObject = selectedContact; + + if (selectedContact.Online && (!(selectedContact is Circle))) + { + sendIMMenuItem.PerformClick(); + } + } + } + } + + private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + if (e.Node.Level == 0) + { + if (e.Node.IsExpanded || (e.Node.ImageIndex == ImageIndexes.Open)) + { + e.Node.Collapse(); + e.Node.ImageIndex = e.Node.SelectedImageIndex = (e.Node.Tag is Circle) ? ImageIndexes.Circle : ImageIndexes.Closed; + } + else if (e.Node.Nodes.Count > 0) + { + e.Node.Expand(); + e.Node.ImageIndex = e.Node.SelectedImageIndex = (e.Node.Tag is Circle) ? ImageIndexes.Circle : ImageIndexes.Open; + } + if (e.Node.Tag is ContactGroup || e.Node.Tag is Circle) + { + propertyGrid.SelectedObject = e.Node.Tag; + } + } + else + { + Contact selectedContact = (Contact)e.Node.Tag; + + if (selectedContact is Circle) + { + if (e.Node.IsExpanded) + { + e.Node.Collapse(); + } + else + { + e.Node.Expand(); + } + } + + propertyGrid.SelectedObject = selectedContact; + } + } + else if (e.Button == MouseButtons.Right) + { + if (e.Node.Tag is Contact && e.Node.Level > 0) + { + treeViewFavoriteList.SelectedNode = e.Node; + Contact contact = (Contact)treeViewFavoriteList.SelectedNode.Tag; + + if (contact.Blocked) + { + blockMenuItem.Visible = false; + unblockMenuItem.Visible = true; + } + else + { + blockMenuItem.Visible = true; + unblockMenuItem.Visible = false; + } + + if (contact.Online) + { + sendIMMenuItem.Visible = true; + sendOIMMenuItem.Visible = false; + + toolStripMenuItem2.Visible = true; + } + else + { + sendIMMenuItem.Visible = false; + sendOIMMenuItem.Visible = true; + + toolStripMenuItem2.Visible = false; + } + + deleteMenuItem.Visible = contact.Guid != Guid.Empty; + + Point point = treeViewFavoriteList.PointToScreen(new Point(e.X, e.Y)); + userMenuStrip.Show(point.X - userMenuStrip.Width, point.Y); + } + else if (e.Node.Tag is ContactGroup) + { + treeViewFavoriteList.SelectedNode = e.Node; + + Point point = treeViewFavoriteList.PointToScreen(new Point(e.X, e.Y)); + groupContextMenu.Show(point.X - groupContextMenu.Width, point.Y); + } + } + } + + private void blockToolStripMenuItem_Click(object sender, EventArgs e) + { + ((Contact)treeViewFavoriteList.SelectedNode.Tag).Blocked = true; + treeViewFavoriteList.SelectedNode.NodeFont = USER_NODE_FONT_BANNED; + } + + private void unblockMenuItem_Click(object sender, EventArgs e) + { + ((Contact)treeViewFavoriteList.SelectedNode.Tag).Blocked = false; + treeViewFavoriteList.SelectedNode.NodeFont = USER_NODE_FONT; + } + + private void deleteMenuItem_Click(object sender, EventArgs e) + { + Contact contact = (Contact)treeViewFavoriteList.SelectedNode.Tag; + RemoveContactForm form = new RemoveContactForm(); + form.FormClosed += delegate(object f, FormClosedEventArgs fce) + { + form = f as RemoveContactForm; + if (DialogResult.OK == form.DialogResult) + { + if (form.Block) + { + contact.Blocked = true; + } + + if (form.RemoveFromAddressBook) + { + messenger.ContactService.RemoveContact(contact); + } + else + { + contact.IsMessengerUser = false; + } + } + }; + form.ShowDialog(this); + } + + private void sendMessageToolStripMenuItem_Click(object sender, EventArgs e) + { + Contact contact = treeViewFavoriteList.SelectedNode.Tag as Contact; + if (!contact.IsMessengerUser) return; + + if (!contact.OnForwardList) + { + AddContactForm acf = new AddContactForm(contact.Mail); + + if (DialogResult.OK == acf.ShowDialog(this) && + acf.Account != String.Empty) + { + messenger.ContactService.AddNewContact(acf.Account, acf.InvitationMessage); + } + + return; + } + + bool activate = false; + ConversationForm activeForm = null; + + if (contact.ClientType != ClientType.EmailMember) + { + foreach (ConversationForm conv in ConversationForms) + { + if (contact.IsSibling(conv.ConversationID.RemoteOwner)) + { + activeForm = conv; + activate = true; + } + } + } + + if (activate) + { + if (activeForm.WindowState == FormWindowState.Minimized || activeForm.Visible == false) + activeForm.Show(); + + activeForm.Activate(); + return; + } + + //Get the conversation identifier, then you can use: + // conversationIdentifier = _messenger.MessageManager.SendTextMessage(ConversationID, message); + //To send a message. + ConversationID conversationIdentifier = Messenger.MessageManager.GetID(contact); + ConversationForm form = CreateConversationForm(contact, conversationIdentifier); + + form.Show(); + } + + private void sendOfflineMessageToolStripMenuItem_Click(object sender, EventArgs e) + { + Contact selectedContact = (Contact)treeViewFavoriteList.SelectedNode.Tag; + this.propertyGrid.SelectedObject = selectedContact; + messenger.OIMService.SendOIMMessage(selectedContact, new TextMessage("MSNPSharp offline message test.")); + + } + + private void sendMIMMenuItem_Click(object sender, EventArgs e) + { + Contact selectedContact = (Contact)treeViewFavoriteList.SelectedNode.Tag; + this.propertyGrid.SelectedObject = selectedContact; + + if (selectedContact.MobileAccess || selectedContact.ClientType == ClientType.PhoneMember) + { + messenger.Nameserver.SendMobileMessage(selectedContact, "MSNP mobile message"); + } + else + MessageBox.Show("This contact is not able to receive mobile messages"); + } + + + private void btnSortBy_Click(object sender, EventArgs e) + { + Button sortByButton = sender as Button; + int x = ((base.Location.X + splitContainer1.Panel1.Width + sortByButton.Left)) + 15; + int y = (base.Location.Y + tableLayoutPanel3.Height + sortByButton.Top) + 3 * btnSortBy.Height; + sortContextMenu.Show(x, y); + sortContextMenu.Focus(); + } + + private void toolStripSortByStatus_Click(object sender, EventArgs e) + { + if (this.toolStripSortByStatus.Checked) + { + treeViewFavoriteList.Nodes.RemoveByKey(ImageIndexes.NoGroupNodeKey); + foreach (ContactGroup cg in messenger.ContactGroups) + { + treeViewFavoriteList.Nodes.RemoveByKey(cg.Guid); + } + + SortByStatus(null); + } + else + { + this.toolStripSortByStatus.Checked = true; + } + } + + private bool initialExpand = true; + + private string GetCircleDisplayName(Circle circle) + { + if (circle == null) + return string.Empty; + + return circle.Name + " (" + circle.ContactList.Values.Count.ToString() + " members)"; + } + + + private void SortByFavAndCircle(Contact contactToUpdate) + { + TreeNode favoritesNode = null; // (0/0) + TreeNode circlesNode = null; // (0/0) + + if (treeViewFavoriteList.Nodes.ContainsKey(ImageIndexes.FavoritesNodeKey)) + { + favoritesNode = treeViewFavoriteList.Nodes[ImageIndexes.FavoritesNodeKey]; + } + else + { + favoritesNode = treeViewFavoriteList.Nodes.Add(ImageIndexes.FavoritesNodeKey, "Favorites", ImageIndexes.Closed, ImageIndexes.Closed); + favoritesNode.NodeFont = PARENT_NODE_FONT; + favoritesNode.Tag = ImageIndexes.FavoritesNodeKey; + } + + if (treeViewFavoriteList.Nodes.ContainsKey(ImageIndexes.CircleNodeKey)) + { + circlesNode = treeViewFavoriteList.Nodes[ImageIndexes.CircleNodeKey]; + } + else + { + circlesNode = treeViewFavoriteList.Nodes.Add(ImageIndexes.CircleNodeKey, "Circles", ImageIndexes.Closed, ImageIndexes.Closed); + circlesNode.NodeFont = PARENT_NODE_FONT; + circlesNode.Tag = ImageIndexes.CircleNodeKey; + } + + if (contactToUpdate == null) + { + // Initial sort + favoritesNode.Nodes.Clear(); + circlesNode.Nodes.Clear(); + + foreach (Circle circle in Messenger.CircleList) + { + TreeNode circleNode = circlesNode.Nodes.Add(circle.Hash, GetCircleDisplayName(circle), ImageIndexes.Circle, ImageIndexes.Circle); + circleNode.NodeFont = circle.Blocked ? PARENT_NODE_FONT_BANNED : PARENT_NODE_FONT; + circleNode.Tag = circle; + + foreach (Contact contact in circle.ContactList.All) + { + // Get real passport contact to chat with... If this contact isn't on our forward list, show add contact form... + string text = contact.Name; + if (contact.PersonalMessage != null && !String.IsNullOrEmpty(contact.PersonalMessage.Message)) + { + text += " - " + contact.PersonalMessage.Message; + } + if (contact.Name != contact.Mail) + { + text += " (" + contact.Mail + ")"; + } + + TreeNode newnode = circleNode.Nodes.Add(contact.Hash, text); + newnode.NodeFont = contact.Blocked ? USER_NODE_FONT_BANNED : USER_NODE_FONT; + newnode.ImageIndex = newnode.SelectedImageIndex = ImageIndexes.GetStatusIndex(contact.Status); + newnode.Tag = contact; + } + } + + ContactGroup favGroup = messenger.ContactGroups.FavoriteGroup; + if (favGroup != null) + { + foreach (Contact c in messenger.ContactList.Forward) + { + if (c.HasGroup(favGroup)) + { + string text = c.Name; + if (c.PersonalMessage != null && !String.IsNullOrEmpty(c.PersonalMessage.Message)) + { + text += " - " + c.PersonalMessage.Message; + } + if (c.Name != c.Mail) + { + text += " (" + c.Mail + ")"; + } + + TreeNode newnode = favoritesNode.Nodes.ContainsKey(c.Hash) ? + favoritesNode.Nodes[c.Hash] : favoritesNode.Nodes.Add(c.Hash, text); + + newnode.NodeFont = c.Blocked ? USER_NODE_FONT_BANNED : USER_NODE_FONT; + newnode.ImageIndex = newnode.SelectedImageIndex = ImageIndexes.GetStatusIndex(c.Status); + newnode.Tag = c; + } + } + } + } + else if (contactToUpdate is Circle) + { + // Circle event + Circle circle = contactToUpdate as Circle; + bool isDeleted = (Messenger.CircleList[circle.AddressBookId, circle.HostDomain] == null); + + if (!isDeleted) + { + TreeNode circlenode = circlesNode.Nodes.ContainsKey(circle.Hash) ? + circlesNode.Nodes[circle.Hash] : circlesNode.Nodes.Add(circle.Hash, GetCircleDisplayName(circle), ImageIndexes.Circle, ImageIndexes.Circle); + + circlenode.NodeFont = circle.Blocked ? PARENT_NODE_FONT_BANNED : PARENT_NODE_FONT; + circlenode.Tag = circle; + + foreach (Contact contact in circle.ContactList.All) + { + // Get real passport contact to chat with... If this contact isn't on our forward list, show add contact form... + string text2 = contact.Name; + if (contact.PersonalMessage != null && !String.IsNullOrEmpty(contact.PersonalMessage.Message)) + { + text2 += " - " + contact.PersonalMessage.Message; + } + if (contact.Name != contact.Mail) + { + text2 += " (" + contact.Mail + ")"; + } + + TreeNode newnode = circlenode.Nodes.ContainsKey(contact.Hash) ? + circlenode.Nodes[contact.Hash] : circlenode.Nodes.Add(contact.Hash, text2); + + newnode.Text = text2; + newnode.ImageIndex = newnode.SelectedImageIndex = ImageIndexes.GetStatusIndex(contact.Status); + newnode.NodeFont = contact.Blocked ? USER_NODE_FONT_BANNED : USER_NODE_FONT; + newnode.Tag = contact; + } + + circlenode.Text = GetCircleDisplayName(circle); + } + else + { + circlesNode.Nodes.RemoveByKey(circle.Hash); + } + } + else + { + // Contact event... Contact is not null. + // Favorite + ContactGroup favGroup = messenger.ContactGroups.FavoriteGroup; + if (favGroup != null && contactToUpdate.HasGroup(favGroup)) + { + Contact contact = messenger.ContactList[contactToUpdate.Mail, contactToUpdate.ClientType]; + string text = contact.Name; + if (contact.PersonalMessage != null && !String.IsNullOrEmpty(contact.PersonalMessage.Message)) + { + text += " - " + contact.PersonalMessage.Message; + } + if (contact.Name != contact.Mail) + { + text += " (" + contact.Mail + ")"; + } + + TreeNode contactNode = favoritesNode.Nodes.ContainsKey(contactToUpdate.Hash) ? + favoritesNode.Nodes[contactToUpdate.Hash] : favoritesNode.Nodes.Add(contactToUpdate.Hash, text); + + contactNode.NodeFont = contact.Blocked ? USER_NODE_FONT_BANNED : USER_NODE_FONT; + contactNode.ImageIndex = contactNode.SelectedImageIndex = ImageIndexes.GetStatusIndex(contactToUpdate.Status); + contactNode.Tag = contactToUpdate; + } + } + + int onlineCount = 0; + foreach (TreeNode nodeFav in favoritesNode.Nodes) + { + if (nodeFav.Tag is Contact && (((Contact)nodeFav.Tag).Online)) + { + onlineCount++; + } + } + string newText = "Favorites (" + onlineCount + "/" + favoritesNode.Nodes.Count + ")"; + if (favoritesNode.Text != newText) + favoritesNode.Text = newText; + + onlineCount = 0; + foreach (TreeNode nodeCircle in circlesNode.Nodes) + { + if (nodeCircle.Tag is Circle && (((Circle)nodeCircle.Tag).Online)) + { + onlineCount++; + } + } + + newText = "Circles (" + onlineCount + "/" + circlesNode.Nodes.Count + ")"; + if (circlesNode.Text != newText) + circlesNode.Text = newText; + } + + private void SortByStatus(Contact contactToUpdate) + { + TreeNode selectedNode = treeViewFavoriteList.SelectedNode; + bool isExpanded = (selectedNode != null && selectedNode.IsExpanded); + + //treeViewFavoriteList.BeginUpdate(); + + if (toolStripSortBygroup.Checked) + toolStripSortBygroup.Checked = false; + + SortByFavAndCircle(contactToUpdate); + + TreeNode onlineNode = null; // (0) + TreeNode mobileNode = null; // (0) + TreeNode offlineNode = null; // (0) + + if (treeViewFavoriteList.Nodes.ContainsKey(ImageIndexes.OnlineNodeKey)) + { + onlineNode = treeViewFavoriteList.Nodes[ImageIndexes.OnlineNodeKey]; + } + else + { + onlineNode = treeViewFavoriteList.Nodes.Add(ImageIndexes.OnlineNodeKey, "Online", ImageIndexes.Closed, ImageIndexes.Closed); + onlineNode.NodeFont = contactToUpdate == null ? PARENT_NODE_FONT : (contactToUpdate.Blocked ? PARENT_NODE_FONT_BANNED : PARENT_NODE_FONT); + onlineNode.Tag = ImageIndexes.OnlineNodeKey; + } + + if (treeViewFavoriteList.Nodes.ContainsKey(ImageIndexes.MobileNodeKey)) + { + mobileNode = treeViewFavoriteList.Nodes[ImageIndexes.MobileNodeKey]; + } + else + { + mobileNode = treeViewFavoriteList.Nodes.Add(ImageIndexes.MobileNodeKey, "Mobile", ImageIndexes.Closed, ImageIndexes.Closed); + mobileNode.NodeFont = PARENT_NODE_FONT; + mobileNode.Tag = ImageIndexes.MobileNodeKey; + } + + if (treeViewFavoriteList.Nodes.ContainsKey(ImageIndexes.OfflineNodeKey)) + { + offlineNode = treeViewFavoriteList.Nodes[ImageIndexes.OfflineNodeKey]; + } + else + { + offlineNode = treeViewFavoriteList.Nodes.Add(ImageIndexes.OfflineNodeKey, "Offline", ImageIndexes.Closed, ImageIndexes.Closed); + offlineNode.NodeFont = PARENT_NODE_FONT; + offlineNode.Tag = ImageIndexes.OfflineNodeKey; + } + + // Re-sort all + if (contactToUpdate == null) + { + mobileNode.Nodes.Clear(); + onlineNode.Nodes.Clear(); + offlineNode.Nodes.Clear(); + + foreach (Contact contact in messenger.ContactList.All) + { + string text = contact.Name; + if (contact.PersonalMessage != null && !String.IsNullOrEmpty(contact.PersonalMessage.Message)) + { + text += " - " + contact.PersonalMessage.Message; + } + if (contact.Name != contact.Mail) + { + text += " (" + contact.Mail + ")"; + } + + TreeNode newnode = contact.Online ? onlineNode.Nodes.Add(contact.Hash, text) : offlineNode.Nodes.Add(contact.Hash, text); + newnode.ImageIndex = newnode.SelectedImageIndex = ImageIndexes.GetStatusIndex(contact.Status); + newnode.NodeFont = contact.Blocked ? USER_NODE_FONT_BANNED : USER_NODE_FONT; + newnode.Tag = contact; + + if (contact.MobileAccess || contact.ClientType == ClientType.PhoneMember) + { + TreeNode newnode2 = mobileNode.Nodes.Add(contact.Hash, text); + newnode2.ImageIndex = newnode2.SelectedImageIndex = ImageIndexes.GetStatusIndex(contact.Status); + newnode2.NodeFont = contact.Blocked ? USER_NODE_FONT_BANNED : USER_NODE_FONT; + newnode2.Tag = contact; + } + } + } + else if ((contactToUpdate is Circle) == false) + { + TreeNode contactNode = null; + + if (contactToUpdate.Online) + { + if (offlineNode.Nodes.ContainsKey(contactToUpdate.Hash)) + { + offlineNode.Nodes.RemoveByKey(contactToUpdate.Hash); + } + if (onlineNode.Nodes.ContainsKey(contactToUpdate.Hash)) + { + contactNode = onlineNode.Nodes[contactToUpdate.Hash]; + } + } + else + { + if (onlineNode.Nodes.ContainsKey(contactToUpdate.Hash)) + { + onlineNode.Nodes.RemoveByKey(contactToUpdate.Hash); + } + if (offlineNode.Nodes.ContainsKey(contactToUpdate.Hash)) + { + contactNode = offlineNode.Nodes[contactToUpdate.Hash]; + } + } + + string text = contactToUpdate.Name; + if (contactToUpdate.PersonalMessage != null && !String.IsNullOrEmpty(contactToUpdate.PersonalMessage.Message)) + { + text += " - " + contactToUpdate.PersonalMessage.Message; + } + if (contactToUpdate.Name != contactToUpdate.Mail) + { + text += " (" + contactToUpdate.Mail + ")"; + } + + if (contactNode == null) + { + contactNode = contactToUpdate.Online ? onlineNode.Nodes.Add(contactToUpdate.Hash, text) : offlineNode.Nodes.Add(contactToUpdate.Hash, text); + } + + if (contactNode.Text != text) + contactNode.Text = text; + + contactNode.ImageIndex = contactNode.SelectedImageIndex = ImageIndexes.GetStatusIndex(contactToUpdate.Status); + contactNode.NodeFont = contactToUpdate.Blocked ? USER_NODE_FONT_BANNED : USER_NODE_FONT; + contactNode.Tag = contactToUpdate; + + if (contactToUpdate.MobileAccess || contactToUpdate.ClientType == ClientType.PhoneMember) + { + TreeNode newnode2 = mobileNode.Nodes.ContainsKey(contactToUpdate.Hash) ? + mobileNode.Nodes[contactToUpdate.Hash] : mobileNode.Nodes.Add(contactToUpdate.Hash, text); + + newnode2.ImageIndex = newnode2.SelectedImageIndex = ImageIndexes.GetStatusIndex(contactToUpdate.Status); + newnode2.NodeFont = contactToUpdate.Blocked ? USER_NODE_FONT_BANNED : USER_NODE_FONT; + newnode2.Tag = contactToUpdate; + } + } + + string newText = "Online (" + onlineNode.Nodes.Count.ToString() + ")"; + if (onlineNode.Text != newText) + onlineNode.Text = newText; + + newText = "Offline (" + offlineNode.Nodes.Count.ToString() + ")"; + if (offlineNode.Text != newText) + offlineNode.Text = newText; + + newText = "Mobile (" + mobileNode.Nodes.Count.ToString() + ")"; + if (mobileNode.Text != newText) + mobileNode.Text = newText; + + treeViewFavoriteList.Sort(); + + if (selectedNode != null) + { + treeViewFavoriteList.SelectedNode = selectedNode; + + if (isExpanded && treeViewFavoriteList.SelectedNode != null) + { + treeViewFavoriteList.SelectedNode.Expand(); + } + } + else + { + if (initialExpand && onlineNode.Nodes.Count > 0) + { + onlineNode.Expand(); + onlineNode.ImageIndex = ImageIndexes.Open; + + initialExpand = false; + } + } + + //treeViewFavoriteList.EndUpdate(); + treeViewFavoriteList.AllowDrop = false; + } + + private void toolStripSortBygroup_Click(object sender, EventArgs e) + { + if (this.toolStripSortBygroup.Checked) + { + treeViewFavoriteList.Nodes.RemoveByKey(ImageIndexes.OnlineNodeKey); + treeViewFavoriteList.Nodes.RemoveByKey(ImageIndexes.MobileNodeKey); + treeViewFavoriteList.Nodes.RemoveByKey(ImageIndexes.OfflineNodeKey); + + SortByGroup(null); + } + else + { + this.toolStripSortBygroup.Checked = true; + } + } + + private void SortByGroup(Contact contactToUpdate) + { + this.treeViewFavoriteList.BeginUpdate(); + this.toolStripSortByStatus.Checked = false; + + SortByFavAndCircle(contactToUpdate); + + foreach (ContactGroup group in this.messenger.ContactGroups) + { + if (group.IsFavorite == false) + { + TreeNode node = treeViewFavoriteList.Nodes.ContainsKey(group.Guid) ? + treeViewFavoriteList.Nodes[group.Guid] : treeViewFavoriteList.Nodes.Add(group.Guid, group.Name, ImageIndexes.Closed, ImageIndexes.Closed); + + node.ImageIndex = ImageIndexes.Closed; + node.NodeFont = PARENT_NODE_FONT; + node.Tag = group; + node.Text = "0"; + } + } + + TreeNode common = treeViewFavoriteList.Nodes.ContainsKey(ImageIndexes.NoGroupNodeKey) ? + treeViewFavoriteList.Nodes[ImageIndexes.NoGroupNodeKey] : treeViewFavoriteList.Nodes.Add(ImageIndexes.NoGroupNodeKey, "Others", 0, 0); + + common.ImageIndex = ImageIndexes.Closed; + common.NodeFont = PARENT_NODE_FONT; + common.Tag = ImageIndexes.NoGroupNodeKey; + common.Text = "0"; + + foreach (Contact contact in messenger.ContactList.All) + { + string text = contact.Name; + if (contact.PersonalMessage != null && !String.IsNullOrEmpty(contact.PersonalMessage.Message)) + { + text += " - " + contact.PersonalMessage.Message; + } + if (contact.Name != contact.Mail) + { + text += " (" + contact.Mail + ")"; + } + + if (contact.ContactGroups.Count == 0) + { + TreeNode newnode = common.Nodes.ContainsKey(contact.Hash) ? + common.Nodes[contact.Hash] : common.Nodes.Add(contact.Hash, text); + + newnode.ImageIndex = newnode.SelectedImageIndex = ImageIndexes.GetStatusIndex(contact.Status); + newnode.NodeFont = contact.Blocked ? USER_NODE_FONT_BANNED : USER_NODE_FONT; + newnode.Tag = contact; + newnode.Text = text; + + if (contact.Online) + common.Text = (Convert.ToInt32(common.Text) + 1).ToString(); + } + else + { + foreach (ContactGroup group in contact.ContactGroups) + { + if (group.IsFavorite == false) + { + TreeNode found = treeViewFavoriteList.Nodes[group.Guid]; + TreeNode newnode = found.Nodes.Add(contact.Hash, contact.Name); + newnode.ImageIndex = newnode.SelectedImageIndex = ImageIndexes.GetStatusIndex(contact.Status); + newnode.NodeFont = contact.Blocked ? USER_NODE_FONT_BANNED : USER_NODE_FONT; + newnode.Tag = contact; + + if (contact.Online) + found.Text = (Convert.ToInt32(found.Text) + 1).ToString(); + } + } + } + } + + foreach (TreeNode nodeGroup in treeViewFavoriteList.Nodes) + { + if (nodeGroup.Tag is ContactGroup) + { + nodeGroup.Text = ((ContactGroup)nodeGroup.Tag).Name + "(" + nodeGroup.Text + "/" + nodeGroup.Nodes.Count + ")"; + } + } + + common.Text = "Others (" + common.Text + "/" + common.Nodes.Count + ")"; + + treeViewFavoriteList.Sort(); + treeViewFavoriteList.EndUpdate(); + treeViewFavoriteList.AllowDrop = true; + } + + private void treeViewFavoriteList_DragEnter(object sender, DragEventArgs e) + { + if (e.Data.GetDataPresent("System.Windows.Forms.TreeNode", false)) + { + e.Effect = DragDropEffects.Move; + } + else + { + e.Effect = DragDropEffects.None; + } + } + + private void treeViewFavoriteList_ItemDrag(object sender, ItemDragEventArgs e) + { + if ((e.Item is TreeNode)/* && (((TreeNode)e.Item).Level > 0)*/) + { + base.DoDragDrop(e.Item, DragDropEffects.Move); + } + } + + private void treeViewFavoriteList_DragOver(object sender, DragEventArgs e) + { + Point pt = ((TreeView)sender).PointToClient(new Point(e.X, e.Y)); + TreeNode nodeAt = ((TreeView)sender).GetNodeAt(pt); + TreeNode data = (TreeNode)e.Data.GetData("System.Windows.Forms.TreeNode"); + if (((data.Level == 0) || (data.Parent == nodeAt)) || (nodeAt.Parent == data.Parent)) + { + e.Effect = DragDropEffects.None; + } + else + { + e.Effect = DragDropEffects.Move; + } + } + + private void treeViewFavoriteList_DragDrop(object sender, DragEventArgs e) + { + if (e.Data.GetDataPresent("System.Windows.Forms.TreeNode", false)) + { + TreeNode contactNode = (TreeNode)e.Data.GetData("System.Windows.Forms.TreeNode"); + if (contactNode.Level != 0) + { + Point pt = ((TreeView)sender).PointToClient(new Point(e.X, e.Y)); + TreeNode newgroupNode = (((TreeView)sender).GetNodeAt(pt).Level == 0) ? ((TreeView)sender).GetNodeAt(pt) : ((TreeView)sender).GetNodeAt(pt).Parent; + TreeNode oldgroupNode = contactNode.Parent; + Contact contact = (Contact)contactNode.Tag; + bool flag = true; + try + { + if (newgroupNode.Tag is ContactGroup) + { + messenger.ContactService.AddContactToGroup(contact, (ContactGroup)newgroupNode.Tag); + } + if (oldgroupNode.Tag is ContactGroup) + { + messenger.ContactService.RemoveContactFromGroup(contact, (ContactGroup)oldgroupNode.Tag); + } + } + catch (Exception) + { + flag = false; + } + + if (flag) + { + treeViewFavoriteList.BeginUpdate(); + TreeNode node3 = (TreeNode)contactNode.Clone(); + newgroupNode.Nodes.Add(node3); + contactNode.Remove(); + treeViewFavoriteList.EndUpdate(); + + newgroupNode.Text = newgroupNode.Text.Split(new char[] { '/' })[0] + "/" + newgroupNode.Nodes.Count + ")"; + oldgroupNode.Text = oldgroupNode.Text.Split(new char[] { '/' })[0] + "/" + oldgroupNode.Nodes.Count + ")"; + } + } + } + } + + private void toolStripDeleteGroup_Click(object sender, EventArgs e) + { + ContactGroup selectedGroup = (ContactGroup)treeViewFavoriteList.SelectedNode.Tag; + this.propertyGrid.SelectedObject = selectedGroup; + + messenger.ContactGroups.Remove(selectedGroup); + + System.Threading.Thread.Sleep(500); + Application.DoEvents(); + System.Threading.Thread.Sleep(500); + + SortByGroup(null); + } + + private void btnAddNew_Click(object sender, EventArgs e) + { + if (this.loginButton.Tag.ToString() != "2") + { + MessageBox.Show("Please sign in first."); + return; + } + + AddContactForm acf = new AddContactForm(String.Empty); + if (DialogResult.OK == acf.ShowDialog(this) && acf.Account != String.Empty) + { + messenger.ContactService.AddNewContact(acf.Account, acf.InvitationMessage); + } + } + + private void createCircleMenuItem_Click(object sender, EventArgs e) + { + //This is a demostration to tell you how to use MSNPSharp to create, block, and unblock Circle. + messenger.ContactService.CreateCircle("test wp circle"); + messenger.ContactService.CreateCircleCompleted += new EventHandler(ContactService_TestingCircleAdded); + } + + void ContactService_TestingCircleAdded(object sender, CircleEventArgs e) + { + //Circle created, then show you how to block. + ////if (!e.Circle.OnBlockedList) + ////{ + //// messenger.ContactService.BlockCircle(e.Circle); + //// e.Circle.ContactBlocked += new EventHandler(Circle_ContactBlocked); + //// Trace.WriteLine("Circle blocked: " + e.Circle.ToString()); + ////} + + ////Trace.WriteLine("Circle created: " + e.Circle.ToString()); + } + + void Circle_ContactBlocked(object sender, EventArgs e) + { + //Circle blocked, show you how to unblock. + Circle circle = sender as Circle; + if (circle != null) + { + messenger.ContactService.UnBlockCircle(circle); + circle.ContactUnBlocked += new EventHandler(circle_ContactUnBlocked); + Trace.WriteLine("Circle unblocked: " + circle.ToString()); + } + } + + void circle_ContactUnBlocked(object sender, EventArgs e) + { + //This demo shows you how to invite a contact to your circle. + if (messenger.ContactList.HasContact("freezingsoft@hotmail.com", ClientType.PassportMember)) + { + messenger.ContactService.InviteCircleMember(sender as Circle, messenger.ContactList["freezingsoft@hotmail.com", ClientType.PassportMember], "hello"); + messenger.ContactService.InviteCircleMemberCompleted += new EventHandler(ContactService_CircleMemberInvited); + } + } + + void ContactService_CircleMemberInvited(object sender, CircleMemberEventArgs e) + { + Trace.WriteLine("Invited: " + e.Member.Hash); + } + + private void importContactsMenuItem_Click(object sender, EventArgs e) + { + ImportContacts ic = new ImportContacts(); + if (ic.ShowDialog(this) == DialogResult.OK) + { + string invitation = ic.InvitationMessage; + foreach (String account in ic.Contacts) + { + messenger.ContactService.AddNewContact(account, invitation); + } + } + } + + private void txtSearch_TextChanged(object sender, EventArgs e) + { + if (txtSearch.Text == String.Empty || txtSearch.Text == "Search contacts") + { + treeViewFilterList.Nodes.Clear(); + treeViewFavoriteList.Visible = true; + treeViewFilterList.Visible = false; + } + else + { + treeViewFilterList.Nodes.Clear(); + treeViewFavoriteList.Visible = false; + treeViewFilterList.Visible = true; + TreeNode foundnode = treeViewFilterList.Nodes.Add("0", "Search Results:"); + + foreach (Contact contact in messenger.ContactList.All) + { + if (contact.Mail.IndexOf(txtSearch.Text, StringComparison.CurrentCultureIgnoreCase) != -1 + || + contact.Name.IndexOf(txtSearch.Text, StringComparison.CurrentCultureIgnoreCase) != -1) + { + TreeNode newnode = foundnode.Nodes.Add(contact.Hash, contact.Name); + newnode.NodeFont = contact.Blocked ? USER_NODE_FONT_BANNED : USER_NODE_FONT; + newnode.Tag = contact; + } + } + foundnode.Text = "Search Results: " + foundnode.Nodes.Count; + foundnode.Expand(); + } + } + + private void txtSearch_Enter(object sender, EventArgs e) + { + if (txtSearch.Text == "Search contacts") + { + txtSearch.Text = String.Empty; + } + } + + private void txtSearch_Leave(object sender, EventArgs e) + { + if (txtSearch.Text == String.Empty) + { + txtSearch.Text = "Search contacts"; + } + } + + private void lblName_Leave(object sender, EventArgs e) + { + string dn = lblName.Text; + string pm = lblPM.Text; + + List lstPersonalMessage = new List(new string[] { "", "" }); + + if (dn != messenger.ContactList.Owner.Name) + { + + lstPersonalMessage[0] = dn; + } + + if (messenger.ContactList.Owner.PersonalMessage == null || pm != messenger.ContactList.Owner.PersonalMessage.Message) + { + lstPersonalMessage[1] = pm; + + } + + Thread updateThread = new Thread(new ParameterizedThreadStart(UpdateProfile)); + updateThread.Start(lstPersonalMessage); + } + + private void comboStatus_KeyPress(object sender, KeyPressEventArgs e) + { + if (!messenger.Connected) + { + login_KeyPress(sender, e); + } + } + + private void displayImageBox_Click(object sender, EventArgs e) + { + if (messenger.Connected) + { + if (openImageDialog.ShowDialog() == DialogResult.OK) + { + Image newImage = Image.FromFile(openImageDialog.FileName, true); + Thread updateThread = new Thread(new ParameterizedThreadStart(UpdateProfile)); + updateThread.Start(newImage); + } + } + } + + private void UpdateProfile(object profileObject) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Updating owner profile, please wait...."); + + if (profileObject is Image) + { + bool updateResult = messenger.StorageService.UpdateProfile(profileObject as Image, "MyPhoto"); + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Update displayimage completed. Result = " + updateResult); + } + + if (profileObject is List) + { + List lstPersonalMessage = profileObject as List; + if (lstPersonalMessage[0] != "") + { + messenger.ContactList.Owner.Name = lstPersonalMessage[0]; + } + + if (lstPersonalMessage[1] != "") + { + messenger.ContactList.Owner.PersonalMessage = new PersonalMessage(lstPersonalMessage[1], MediaType.None, null, NSMessageHandler.MachineGuid); + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Update personal message completed."); + } + } + + private void btnSetMusic_Click(object sender, EventArgs e) + { + MusicForm musicForm = new MusicForm(); + if (musicForm.ShowDialog() == DialogResult.OK) + { + Messenger.ContactList.Owner.PersonalMessage = new PersonalMessage( + Messenger.ContactList.Owner.PersonalMessage.Message, + MediaType.Music, + new string[] { musicForm.Artist, musicForm.Song, musicForm.Album, "" }, + NSMessageHandler.MachineGuid); + } + } + + + } +} diff --git a/Example/DotMSNClient.csproj b/Example/DotMSNClient.csproj new file mode 100644 index 0000000..b9b26b0 --- /dev/null +++ b/Example/DotMSNClient.csproj @@ -0,0 +1,257 @@ + + + + Local + 8.0.50727 + 2.0 + {BDF3E472-EFE8-44D6-AFB6-062DD929D56F} + Debug + AnyCPU + MSNPSharp_logo.ico + + + DotMSNClient + JScript + Grid + IE50 + false + WinExe + MSNPSharpClient + OnBuildSuccess + MSNPSharpClient.ClientForm + + + + + v2.0 + 2.0 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + bin\Debug\ + 285212672 + + + TRACE;DEBUG + + + true + 4096 + false + false + false + 4 + full + prompt + AllRules.ruleset + + + bin\Release\ + 285212672 + + + TRACE + + + 4096 + true + false + false + 4 + none + prompt + AllRules.ruleset + + + + System + + + System.Data + + + System.Drawing + + + + + System.Windows.Forms + + + System.XML + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Form + + + AddContactForm.cs + + + Form + + + Form + + + FileTransferForm.cs + + + Form + + + DotMSNClient.cs + + + Form + + + ImportContacts.cs + + + Form + + + MusicForm.cs + + + + True + True + Resources.resx + + + Form + + + RemoveContactForm.cs + + + Form + + + ReverseAddedForm.cs + + + Component + + + Form + + + TraceForm.cs + + + Designer + AddContactForm.cs + + + ConversationForm.cs + Designer + + + FileTransferForm.cs + Designer + + + DotMSNClient.cs + Designer + + + Designer + ImportContacts.cs + + + Designer + MusicForm.cs + + + Designer + ResXFileCodeGenerator + Resources.Designer.cs + + + Designer + RemoveContactForm.cs + + + Designer + ReverseAddedForm.cs + + + Designer + TraceForm.cs + + + + + {97CB2DC7-2FE8-4AF5-84D0-6B9872A5E960} + MSNPSharp + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + + + + + + \ No newline at end of file diff --git a/Example/DotMSNClient.csproj.user b/Example/DotMSNClient.csproj.user new file mode 100644 index 0000000..6f23531 --- /dev/null +++ b/Example/DotMSNClient.csproj.user @@ -0,0 +1,13 @@ + + + + + + + + + + en-US + false + + \ No newline at end of file diff --git a/Example/DotMSNClient.resx b/Example/DotMSNClient.resx new file mode 100644 index 0000000..19a2329 --- /dev/null +++ b/Example/DotMSNClient.resx @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 118, 17 + + + 776, 17 + + + 506, 17 + + + 228, 17 + + + 639, 17 + + + 17, 17 + + + 17, 56 + + + 163, 56 + + + 322, 56 + + + 76 + + \ No newline at end of file diff --git a/Example/FileTransferForm.Designer.cs b/Example/FileTransferForm.Designer.cs new file mode 100644 index 0000000..da2292e --- /dev/null +++ b/Example/FileTransferForm.Designer.cs @@ -0,0 +1,164 @@ +namespace MSNPSharpClient +{ + partial class FileTransferForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.lblFile = new System.Windows.Forms.Label(); + this.txtFilePath = new System.Windows.Forms.TextBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.progressBar = new System.Windows.Forms.ProgressBar(); + this.button1 = new System.Windows.Forms.Button(); + this.saveFileDialog = new System.Windows.Forms.SaveFileDialog(); + this.label1 = new System.Windows.Forms.Label(); + this.lblSize = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // lblFile + // + this.lblFile.AutoSize = true; + this.lblFile.Location = new System.Drawing.Point(18, 8); + this.lblFile.Name = "lblFile"; + this.lblFile.Size = new System.Drawing.Size(29, 12); + this.lblFile.TabIndex = 0; + this.lblFile.Text = "File"; + // + // txtFilePath + // + this.txtFilePath.Location = new System.Drawing.Point(64, 6); + this.txtFilePath.Name = "txtFilePath"; + this.txtFilePath.Size = new System.Drawing.Size(270, 21); + this.txtFilePath.TabIndex = 3; + this.txtFilePath.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + // + // btnOK + // + this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; + this.btnOK.Location = new System.Drawing.Point(64, 94); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(164, 37); + this.btnOK.TabIndex = 6; + this.btnOK.Tag = "OK"; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + this.btnOK.Click += new System.EventHandler(this.btnOK_Click); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(237, 94); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(97, 37); + this.btnCancel.TabIndex = 7; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); + // + // progressBar + // + this.progressBar.Location = new System.Drawing.Point(64, 56); + this.progressBar.Name = "progressBar"; + this.progressBar.Size = new System.Drawing.Size(270, 21); + this.progressBar.Step = 1; + this.progressBar.TabIndex = 8; + this.progressBar.Visible = false; + // + // button1 + // + this.button1.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button1.Location = new System.Drawing.Point(254, 30); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(80, 21); + this.button1.TabIndex = 9; + this.button1.Text = "Browse..."; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // saveFileDialog + // + this.saveFileDialog.Filter = "*.*|*.*"; + this.saveFileDialog.RestoreDirectory = true; + this.saveFileDialog.Title = "Save as..."; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(18, 34); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(29, 12); + this.label1.TabIndex = 10; + this.label1.Text = "Size"; + // + // lblSize + // + this.lblSize.AutoSize = true; + this.lblSize.Location = new System.Drawing.Point(61, 34); + this.lblSize.Name = "lblSize"; + this.lblSize.Size = new System.Drawing.Size(35, 12); + this.lblSize.TabIndex = 11; + this.lblSize.Text = "bytes"; + // + // FileTransferForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(345, 142); + this.ControlBox = false; + this.Controls.Add(this.lblSize); + this.Controls.Add(this.label1); + this.Controls.Add(this.button1); + this.Controls.Add(this.progressBar); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.txtFilePath); + this.Controls.Add(this.lblFile); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FileTransferForm"; + this.Text = "File Transfer"; + this.Load += new System.EventHandler(this.FileTransferForm_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FileTransferForm_FormClosing); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label lblFile; + private System.Windows.Forms.TextBox txtFilePath; + private System.Windows.Forms.Button btnOK; + private System.Windows.Forms.Button btnCancel; + private System.Windows.Forms.ProgressBar progressBar; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.SaveFileDialog saveFileDialog; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label lblSize; + } +} \ No newline at end of file diff --git a/Example/FileTransferForm.cs b/Example/FileTransferForm.cs new file mode 100644 index 0000000..cad3cb0 --- /dev/null +++ b/Example/FileTransferForm.cs @@ -0,0 +1,172 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using System.Diagnostics; + +namespace MSNPSharpClient +{ + using MSNPSharp; + using MSNPSharp.Core; + using MSNPSharp.DataTransfer; + + + public partial class FileTransferForm : Form + { + MSNSLPInvitationEventArgs invite; + private bool transferFinished; + + public FileTransferForm(MSNSLPInvitationEventArgs invite) + { + this.invite = invite; + InitializeComponent(); + } + + private void FileTransferForm_Load(object sender, EventArgs e) + { + string appPath = Path.GetFullPath("."); + + Text = "File Transfer: " + invite.TransferProperties.RemoteContact.Mail; + txtFilePath.Text = Path.Combine(appPath, invite.Filename); + lblSize.Text = invite.FileSize.ToString() + " bytes"; + + invite.TransferSession.TransferStarted += (TransferSession_TransferStarted); + invite.TransferSession.TransferProgressed += (TransferSession_TransferProgressed); + invite.TransferSession.TransferAborted += (TransferSession_TransferAborted); + invite.TransferSession.TransferFinished += (TransferSession_TransferFinished); + } + + void TransferSession_TransferStarted(object sender, EventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(TransferSession_TransferStarted), sender, e); + return; + } + + progressBar.Visible = true; + lblSize.Text = "Transfer started"; + } + + void TransferSession_TransferProgressed(object sender, P2PTransferProgressedEventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(TransferSession_TransferProgressed), sender, e); + return; + } + progressBar.Visible = true; + progressBar.Value = e.Percent; + lblSize.Text = "Transferred: " + e.Transferred + " / " + e.TotalSize; + } + + void TransferSession_TransferFinished(object sender, EventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(TransferSession_TransferFinished), sender, e); + return; + } + + transferFinished = true; + + btnOK.Text = "Open File"; + btnOK.Tag = "OPENFILE"; + btnCancel.Visible = true; + + lblSize.Text = "Transfer finished"; + progressBar.Visible = false; + progressBar.Value = 0; + } + + void TransferSession_TransferAborted(object sender, EventArgs e) + { + if (InvokeRequired) + { + Invoke(new EventHandler(TransferSession_TransferAborted), sender, e); + return; + } + + btnOK.Text = "Close"; + btnOK.Tag = "CLOSE"; + lblSize.Text = "Transfer aborted"; + + progressBar.Visible = false; + progressBar.Value = 0; + + } + + private void button1_Click(object sender, EventArgs e) + { + if (saveFileDialog.ShowDialog() == DialogResult.OK) + { + txtFilePath.Text = saveFileDialog.FileName; + } + } + + private void btnCancel_Click(object sender, EventArgs e) + { + if (transferFinished) + { + Close(); + } + else + { + invite.Accept = false; + invite.TransferHandler.RejectTransfer(invite); + + btnCancel.Visible = false; + Close(); + } + } + + private void btnOK_Click(object sender, EventArgs e) + { + switch (btnOK.Tag.ToString()) + { + case "OK": + + invite.TransferSession.DataStream = new FileStream(txtFilePath.Text, FileMode.Create, FileAccess.Write); + invite.TransferSession.AutoCloseStream = true; + invite.Accept = true; + invite.TransferHandler.AcceptTransfer(invite); + + btnCancel.Visible = false; + + lblSize.Text = "Waiting to start..."; + + btnOK.Text = "Abort Transfer"; + btnOK.Tag = "ABORT"; + break; + + case "ABORT": + invite.TransferHandler.CloseSession(invite.TransferSession); + btnOK.Text = "Close"; + btnOK.Tag = "CLOSE"; + break; + + case "OPENFILE": + Process.Start(txtFilePath.Text); + Close(); + break; + + case "CLOSE": + Close(); + break; + } + } + + private void FileTransferForm_FormClosing(object sender, FormClosingEventArgs e) + { + invite.TransferSession.TransferStarted -= (TransferSession_TransferStarted); + invite.TransferSession.TransferProgressed -= (TransferSession_TransferProgressed); + invite.TransferSession.TransferAborted -= (TransferSession_TransferAborted); + invite.TransferSession.TransferFinished -= (TransferSession_TransferFinished); + } + + } +}; \ No newline at end of file diff --git a/Example/FileTransferForm.resx b/Example/FileTransferForm.resx new file mode 100644 index 0000000..d957dca --- /dev/null +++ b/Example/FileTransferForm.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/Example/ImportContacts.Designer.cs b/Example/ImportContacts.Designer.cs new file mode 100644 index 0000000..f3e9914 --- /dev/null +++ b/Example/ImportContacts.Designer.cs @@ -0,0 +1,120 @@ +namespace MSNPSharpClient +{ + partial class ImportContacts + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); + this.lblInvitation = new System.Windows.Forms.Label(); + this.txtInvitation = new System.Windows.Forms.TextBox(); + this.browseFile = new System.Windows.Forms.Button(); + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // openFileDialog + // + this.openFileDialog.DefaultExt = "ctt"; + this.openFileDialog.Filter = "Messenger Contact List|*.ctt"; + this.openFileDialog.Title = "Select Contact File"; + // + // lblInvitation + // + this.lblInvitation.AutoSize = true; + this.lblInvitation.Location = new System.Drawing.Point(12, 20); + this.lblInvitation.Name = "lblInvitation"; + this.lblInvitation.Size = new System.Drawing.Size(96, 13); + this.lblInvitation.TabIndex = 0; + this.lblInvitation.Text = "Invitation Message"; + // + // txtInvitation + // + this.txtInvitation.Location = new System.Drawing.Point(114, 17); + this.txtInvitation.Name = "txtInvitation"; + this.txtInvitation.Size = new System.Drawing.Size(342, 20); + this.txtInvitation.TabIndex = 1; + this.txtInvitation.Text = "Accept me :)"; + // + // browseFile + // + this.browseFile.Location = new System.Drawing.Point(114, 43); + this.browseFile.Name = "browseFile"; + this.browseFile.Size = new System.Drawing.Size(134, 23); + this.browseFile.TabIndex = 2; + this.browseFile.Text = "Browse Contact File..."; + this.browseFile.UseVisualStyleBackColor = true; + this.browseFile.Click += new System.EventHandler(this.browseFile_Click); + // + // button1 + // + this.button1.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button1.Location = new System.Drawing.Point(283, 73); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(84, 23); + this.button1.TabIndex = 3; + this.button1.Text = "OK"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button_Click); + // + // button2 + // + this.button2.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button2.Location = new System.Drawing.Point(373, 73); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(83, 23); + this.button2.TabIndex = 4; + this.button2.Text = "Cancel"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button_Click); + // + // ImportContacts + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(466, 108); + this.Controls.Add(this.button2); + this.Controls.Add(this.button1); + this.Controls.Add(this.browseFile); + this.Controls.Add(this.txtInvitation); + this.Controls.Add(this.lblInvitation); + this.Name = "ImportContacts"; + this.Text = "Import Contacts"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.OpenFileDialog openFileDialog; + private System.Windows.Forms.Label lblInvitation; + private System.Windows.Forms.TextBox txtInvitation; + private System.Windows.Forms.Button browseFile; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; + } +} \ No newline at end of file diff --git a/Example/ImportContacts.cs b/Example/ImportContacts.cs new file mode 100644 index 0000000..8df59d5 --- /dev/null +++ b/Example/ImportContacts.cs @@ -0,0 +1,73 @@ +using System; +using System.IO; +using System.Xml; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using MSNPSharp; + +namespace MSNPSharpClient +{ + public partial class ImportContacts : Form + { + public ImportContacts() + { + InitializeComponent(); + } + + + private string invitationMessage = String.Empty; + public string InvitationMessage + { + get + { + return invitationMessage; + } + } + + private List _contacts = new List(); + public List Contacts + { + get + { + return _contacts; + } + } + + private void browseFile_Click(object sender, EventArgs e) + { + if (DialogResult.OK == openFileDialog.ShowDialog(this)) + { + Contacts.Clear(); + invitationMessage = txtInvitation.Text; + try + { + XmlDocument doc = new XmlDocument(); + doc.LoadXml(File.ReadAllText(openFileDialog.FileName)); + + XmlNodeList contacts = doc.GetElementsByTagName("contact"); + foreach (XmlNode contactNode in contacts) + { + if (ClientType.PassportMember == (ClientType)Convert.ToInt32(contactNode.Attributes["type"].Value)) + { + Contacts.Add(contactNode.InnerText.ToLower(System.Globalization.CultureInfo.InvariantCulture)); + } + } + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + MessageBox.Show(Contacts.Count.ToString() + " contacts to be imported."); + } + } + + private void button_Click(object sender, EventArgs e) + { + Close(); + } + } +} \ No newline at end of file diff --git a/Example/ImportContacts.resx b/Example/ImportContacts.resx new file mode 100644 index 0000000..f901ebb --- /dev/null +++ b/Example/ImportContacts.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/Example/MSNPSharp_logo.ico b/Example/MSNPSharp_logo.ico new file mode 100644 index 0000000..7ba3fdb Binary files /dev/null and b/Example/MSNPSharp_logo.ico differ diff --git a/Example/MusicForm.Designer.cs b/Example/MusicForm.Designer.cs new file mode 100644 index 0000000..1de16ea --- /dev/null +++ b/Example/MusicForm.Designer.cs @@ -0,0 +1,142 @@ +namespace MSNPSharpClient +{ + partial class MusicForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.lblArtist = new System.Windows.Forms.Label(); + this.lblSong = new System.Windows.Forms.Label(); + this.lblAlbum = new System.Windows.Forms.Label(); + this.txtArtist = new System.Windows.Forms.TextBox(); + this.txtSong = new System.Windows.Forms.TextBox(); + this.txtAlbum = new System.Windows.Forms.TextBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // lblArtist + // + this.lblArtist.AutoSize = true; + this.lblArtist.Location = new System.Drawing.Point(18, 9); + this.lblArtist.Name = "lblArtist"; + this.lblArtist.Size = new System.Drawing.Size(30, 13); + this.lblArtist.TabIndex = 0; + this.lblArtist.Text = "Artist"; + // + // lblSong + // + this.lblSong.AutoSize = true; + this.lblSong.Location = new System.Drawing.Point(16, 35); + this.lblSong.Name = "lblSong"; + this.lblSong.Size = new System.Drawing.Size(32, 13); + this.lblSong.TabIndex = 1; + this.lblSong.Text = "Song"; + // + // lblAlbum + // + this.lblAlbum.AutoSize = true; + this.lblAlbum.Location = new System.Drawing.Point(12, 59); + this.lblAlbum.Name = "lblAlbum"; + this.lblAlbum.Size = new System.Drawing.Size(36, 13); + this.lblAlbum.TabIndex = 2; + this.lblAlbum.Text = "Album"; + // + // txtArtist + // + this.txtArtist.Location = new System.Drawing.Point(64, 6); + this.txtArtist.Name = "txtArtist"; + this.txtArtist.Size = new System.Drawing.Size(297, 20); + this.txtArtist.TabIndex = 3; + // + // txtSong + // + this.txtSong.Location = new System.Drawing.Point(64, 32); + this.txtSong.Name = "txtSong"; + this.txtSong.Size = new System.Drawing.Size(297, 20); + this.txtSong.TabIndex = 4; + // + // txtAlbum + // + this.txtAlbum.Location = new System.Drawing.Point(64, 56); + this.txtAlbum.Name = "txtAlbum"; + this.txtAlbum.Size = new System.Drawing.Size(297, 20); + this.txtAlbum.TabIndex = 5; + // + // btnOK + // + this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; + this.btnOK.Location = new System.Drawing.Point(204, 82); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(75, 23); + this.btnOK.TabIndex = 6; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(285, 82); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(76, 23); + this.btnCancel.TabIndex = 7; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // MusicForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(374, 113); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.txtAlbum); + this.Controls.Add(this.txtSong); + this.Controls.Add(this.txtArtist); + this.Controls.Add(this.lblAlbum); + this.Controls.Add(this.lblSong); + this.Controls.Add(this.lblArtist); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "MusicForm"; + this.Text = "I am Listening..."; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label lblArtist; + private System.Windows.Forms.Label lblSong; + private System.Windows.Forms.Label lblAlbum; + private System.Windows.Forms.TextBox txtArtist; + private System.Windows.Forms.TextBox txtSong; + private System.Windows.Forms.TextBox txtAlbum; + private System.Windows.Forms.Button btnOK; + private System.Windows.Forms.Button btnCancel; + } +} \ No newline at end of file diff --git a/Example/MusicForm.cs b/Example/MusicForm.cs new file mode 100644 index 0000000..b4b177d --- /dev/null +++ b/Example/MusicForm.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +namespace MSNPSharpClient +{ + public partial class MusicForm : Form + { + public MusicForm() + { + InitializeComponent(); + } + + + public string Artist + { + get + { + return txtArtist.Text; + } + } + + public string Song + { + get + { + return txtSong.Text; + } + } + + public string Album + { + get + { + return txtSong.Text; + } + } + + } +} \ No newline at end of file diff --git a/Example/MusicForm.resx b/Example/MusicForm.resx new file mode 100644 index 0000000..19dc0dd --- /dev/null +++ b/Example/MusicForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Example/Properties/AssemblyInfo.cs b/Example/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2d78b1d --- /dev/null +++ b/Example/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: ComVisibleAttribute(false)] +[assembly: CLSCompliantAttribute(false)] +[assembly: AssemblyTitleAttribute("MSNPSharp Example Client")] +[assembly: AssemblyDescriptionAttribute(".NET MSN Messenger library Example Client")] +[assembly: AssemblyCopyrightAttribute("Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice.")] +[assembly: AssemblyProductAttribute("MSNPSharp")] +[assembly: AssemblyDelaySignAttribute(false)] +[assembly: GuidAttribute("FAE04EC0-301F-11D3-BF4B-00C04F79EFBC")] + +// Version information for an assembly consists of the following four values: +// Major.Minor.Build.SVNRevision +[assembly: AssemblyVersionAttribute("3.2.1.2668")] +[assembly: AssemblyFileVersionAttribute("3.2.1.2668")] +[assembly: AssemblyCompanyAttribute("MSNPSharp")] +[assembly: AssemblyTrademarkAttribute("MSNPSharp")] diff --git a/Example/Properties/Resources.Designer.cs b/Example/Properties/Resources.Designer.cs new file mode 100644 index 0000000..4eaef34 --- /dev/null +++ b/Example/Properties/Resources.Designer.cs @@ -0,0 +1,303 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MSNPSharpClient.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MSNPSharpClient.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap app_banner { + get { + object obj = ResourceManager.GetObject("app_banner", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap away { + get { + object obj = ResourceManager.GetObject("away", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap biggrin { + get { + object obj = ResourceManager.GetObject("biggrin", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap busy { + get { + object obj = ResourceManager.GetObject("busy", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap circle { + get { + object obj = ResourceManager.GetObject("circle", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap closed { + get { + object obj = ResourceManager.GetObject("closed", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap Color_fontHS { + get { + object obj = ResourceManager.GetObject("Color_fontHS", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap file { + get { + object obj = ResourceManager.GetObject("file", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap hidden { + get { + object obj = ResourceManager.GetObject("hidden", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap idle { + get { + object obj = ResourceManager.GetObject("idle", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap inner_emoticon { + get { + object obj = ResourceManager.GetObject("inner_emoticon", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap loading { + get { + object obj = ResourceManager.GetObject("loading", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon msn_ico { + get { + object obj = ResourceManager.GetObject("msn_ico", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon MSNPSharp_logo_small_ico { + get { + object obj = ResourceManager.GetObject("MSNPSharp_logo_small_ico", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap nudge { + get { + object obj = ResourceManager.GetObject("nudge", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap offline { + get { + object obj = ResourceManager.GetObject("offline", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap online { + get { + object obj = ResourceManager.GetObject("online", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap open { + get { + object obj = ResourceManager.GetObject("open", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap sad { + get { + object obj = ResourceManager.GetObject("sad", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap smiley { + get { + object obj = ResourceManager.GetObject("smiley", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap tongueout { + get { + object obj = ResourceManager.GetObject("tongueout", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap wink { + get { + object obj = ResourceManager.GetObject("wink", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon yahoo_ico { + get { + object obj = ResourceManager.GetObject("yahoo_ico", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap YahooMessenger_logo { + get { + object obj = ResourceManager.GetObject("YahooMessenger_logo", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/Example/Properties/Resources.resx b/Example/Properties/Resources.resx new file mode 100644 index 0000000..fe10750 --- /dev/null +++ b/Example/Properties/Resources.resx @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\yahoo_ico.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\smileys\sad.gif;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\nudge.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\MSNPSharp_logo_small.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\smileys\biggrin.gif;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\status\away.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\msn_ico.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\status\idle.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\loading.gif;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\smileys\wink.gif;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\status\busy.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\status\hidden.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\status\online.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\file.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\status\offline.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\status\circle.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\status\closed.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\YahooMessenger_logo.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\status\open.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\smileys\tongueout.gif;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\smileys\smiley.gif;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\inner_emoicon.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\app_banner.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Color_fontHS.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/Example/RemoveContactForm.Designer.cs b/Example/RemoveContactForm.Designer.cs new file mode 100644 index 0000000..56e6e8c --- /dev/null +++ b/Example/RemoveContactForm.Designer.cs @@ -0,0 +1,102 @@ +namespace MSNPSharpClient +{ + partial class RemoveContactForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.cbRemove = new System.Windows.Forms.CheckBox(); + this.cbBlock = new System.Windows.Forms.CheckBox(); + this.btnRemove = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // cbRemove + // + this.cbRemove.AutoSize = true; + this.cbRemove.Location = new System.Drawing.Point(12, 21); + this.cbRemove.Name = "cbRemove"; + this.cbRemove.Size = new System.Drawing.Size(201, 17); + this.cbRemove.TabIndex = 0; + this.cbRemove.Text = "Remove this user from my contact list"; + this.cbRemove.UseVisualStyleBackColor = true; + // + // cbBlock + // + this.cbBlock.AutoSize = true; + this.cbBlock.Location = new System.Drawing.Point(12, 44); + this.cbBlock.Name = "cbBlock"; + this.cbBlock.Size = new System.Drawing.Size(75, 17); + this.cbBlock.TabIndex = 1; + this.cbBlock.Text = "Also block"; + this.cbBlock.UseVisualStyleBackColor = true; + // + // btnRemove + // + this.btnRemove.DialogResult = System.Windows.Forms.DialogResult.OK; + this.btnRemove.Location = new System.Drawing.Point(24, 76); + this.btnRemove.Name = "btnRemove"; + this.btnRemove.Size = new System.Drawing.Size(99, 23); + this.btnRemove.TabIndex = 2; + this.btnRemove.Text = "Remove contact"; + this.btnRemove.UseVisualStyleBackColor = true; + this.btnRemove.Click += new System.EventHandler(this.btn_Click); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(129, 76); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(75, 23); + this.btnCancel.TabIndex = 3; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + this.btnCancel.Click += new System.EventHandler(this.btn_Click); + // + // RemoveContactForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(217, 113); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnRemove); + this.Controls.Add(this.cbBlock); + this.Controls.Add(this.cbRemove); + this.Name = "RemoveContactForm"; + this.Text = "Remove Contact"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.CheckBox cbRemove; + private System.Windows.Forms.CheckBox cbBlock; + private System.Windows.Forms.Button btnRemove; + private System.Windows.Forms.Button btnCancel; + } +} \ No newline at end of file diff --git a/Example/RemoveContactForm.cs b/Example/RemoveContactForm.cs new file mode 100644 index 0000000..2892ab5 --- /dev/null +++ b/Example/RemoveContactForm.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +namespace MSNPSharpClient +{ + public partial class RemoveContactForm : Form + { + + public bool RemoveFromAddressBook + { + get + { + return cbRemove.Checked; + } + } + + public bool Block + { + get + { + return cbBlock.Checked; + } + } + + public RemoveContactForm() + { + InitializeComponent(); + } + + private void btn_Click(object sender, EventArgs e) + { + Close(); + } + } +} \ No newline at end of file diff --git a/Example/RemoveContactForm.resx b/Example/RemoveContactForm.resx new file mode 100644 index 0000000..19dc0dd --- /dev/null +++ b/Example/RemoveContactForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Example/Resources/Color_fontHS.png b/Example/Resources/Color_fontHS.png new file mode 100644 index 0000000..0a7695d Binary files /dev/null and b/Example/Resources/Color_fontHS.png differ diff --git a/Example/Resources/MSNPSharp_logo.ico b/Example/Resources/MSNPSharp_logo.ico new file mode 100644 index 0000000..7ba3fdb Binary files /dev/null and b/Example/Resources/MSNPSharp_logo.ico differ diff --git a/Example/Resources/MSNPSharp_logo_small.ico b/Example/Resources/MSNPSharp_logo_small.ico new file mode 100644 index 0000000..47a55c5 Binary files /dev/null and b/Example/Resources/MSNPSharp_logo_small.ico differ diff --git a/Example/Resources/YahooMessenger_logo.png b/Example/Resources/YahooMessenger_logo.png new file mode 100644 index 0000000..3ca721d Binary files /dev/null and b/Example/Resources/YahooMessenger_logo.png differ diff --git a/Example/Resources/app_banner.png b/Example/Resources/app_banner.png new file mode 100644 index 0000000..c4b38d8 Binary files /dev/null and b/Example/Resources/app_banner.png differ diff --git a/Example/Resources/file.png b/Example/Resources/file.png new file mode 100644 index 0000000..c07f629 Binary files /dev/null and b/Example/Resources/file.png differ diff --git a/Example/Resources/inner_emoicon.png b/Example/Resources/inner_emoicon.png new file mode 100644 index 0000000..ed88b96 Binary files /dev/null and b/Example/Resources/inner_emoicon.png differ diff --git a/Example/Resources/loading.gif b/Example/Resources/loading.gif new file mode 100644 index 0000000..3288d10 Binary files /dev/null and b/Example/Resources/loading.gif differ diff --git a/Example/Resources/msn_ico.ico b/Example/Resources/msn_ico.ico new file mode 100644 index 0000000..b0047c8 Binary files /dev/null and b/Example/Resources/msn_ico.ico differ diff --git a/Example/Resources/nudge.png b/Example/Resources/nudge.png new file mode 100644 index 0000000..a18c944 Binary files /dev/null and b/Example/Resources/nudge.png differ diff --git a/Example/Resources/smileys/biggrin.gif b/Example/Resources/smileys/biggrin.gif new file mode 100644 index 0000000..5e490d1 Binary files /dev/null and b/Example/Resources/smileys/biggrin.gif differ diff --git a/Example/Resources/smileys/sad.gif b/Example/Resources/smileys/sad.gif new file mode 100644 index 0000000..cb59b62 Binary files /dev/null and b/Example/Resources/smileys/sad.gif differ diff --git a/Example/Resources/smileys/smiley.gif b/Example/Resources/smileys/smiley.gif new file mode 100644 index 0000000..46bafcd Binary files /dev/null and b/Example/Resources/smileys/smiley.gif differ diff --git a/Example/Resources/smileys/tongueout.gif b/Example/Resources/smileys/tongueout.gif new file mode 100644 index 0000000..b96d15d Binary files /dev/null and b/Example/Resources/smileys/tongueout.gif differ diff --git a/Example/Resources/smileys/wink.gif b/Example/Resources/smileys/wink.gif new file mode 100644 index 0000000..dfc35cc Binary files /dev/null and b/Example/Resources/smileys/wink.gif differ diff --git a/Example/Resources/status/away.png b/Example/Resources/status/away.png new file mode 100644 index 0000000..5966f74 Binary files /dev/null and b/Example/Resources/status/away.png differ diff --git a/Example/Resources/status/busy.png b/Example/Resources/status/busy.png new file mode 100644 index 0000000..1fdf421 Binary files /dev/null and b/Example/Resources/status/busy.png differ diff --git a/Example/Resources/status/circle.png b/Example/Resources/status/circle.png new file mode 100644 index 0000000..2840701 Binary files /dev/null and b/Example/Resources/status/circle.png differ diff --git a/Example/Resources/status/closed.png b/Example/Resources/status/closed.png new file mode 100644 index 0000000..614a23e Binary files /dev/null and b/Example/Resources/status/closed.png differ diff --git a/Example/Resources/status/hidden.png b/Example/Resources/status/hidden.png new file mode 100644 index 0000000..a41b641 Binary files /dev/null and b/Example/Resources/status/hidden.png differ diff --git a/Example/Resources/status/idle.png b/Example/Resources/status/idle.png new file mode 100644 index 0000000..ecd3b4d Binary files /dev/null and b/Example/Resources/status/idle.png differ diff --git a/Example/Resources/status/offline.png b/Example/Resources/status/offline.png new file mode 100644 index 0000000..854fe7f Binary files /dev/null and b/Example/Resources/status/offline.png differ diff --git a/Example/Resources/status/online.png b/Example/Resources/status/online.png new file mode 100644 index 0000000..1efefd3 Binary files /dev/null and b/Example/Resources/status/online.png differ diff --git a/Example/Resources/status/open.png b/Example/Resources/status/open.png new file mode 100644 index 0000000..d2d9210 Binary files /dev/null and b/Example/Resources/status/open.png differ diff --git a/Example/Resources/yahoo_ico.ico b/Example/Resources/yahoo_ico.ico new file mode 100644 index 0000000..b51c74b Binary files /dev/null and b/Example/Resources/yahoo_ico.ico differ diff --git a/Example/ReverseAddedForm.Designer.cs b/Example/ReverseAddedForm.Designer.cs new file mode 100644 index 0000000..a330ba6 --- /dev/null +++ b/Example/ReverseAddedForm.Designer.cs @@ -0,0 +1,151 @@ +namespace MSNPSharpClient +{ + partial class ReverseAddedForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.lblAdded = new System.Windows.Forms.Label(); + this.gbMembership = new System.Windows.Forms.GroupBox(); + this.rbBlock = new System.Windows.Forms.RadioButton(); + this.rbAllow = new System.Windows.Forms.RadioButton(); + this.cbContactList = new System.Windows.Forms.CheckBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.gbMembership.SuspendLayout(); + this.SuspendLayout(); + // + // lblAdded + // + this.lblAdded.AutoSize = true; + this.lblAdded.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(162))); + this.lblAdded.Location = new System.Drawing.Point(12, 9); + this.lblAdded.Name = "lblAdded"; + this.lblAdded.Size = new System.Drawing.Size(226, 13); + this.lblAdded.TabIndex = 0; + this.lblAdded.Text = "{0} has added you to their contact list."; + // + // gbMembership + // + this.gbMembership.Controls.Add(this.rbBlock); + this.gbMembership.Controls.Add(this.rbAllow); + this.gbMembership.Location = new System.Drawing.Point(15, 36); + this.gbMembership.Name = "gbMembership"; + this.gbMembership.Size = new System.Drawing.Size(441, 74); + this.gbMembership.TabIndex = 1; + this.gbMembership.TabStop = false; + this.gbMembership.Text = "Add contact to:"; + // + // rbBlock + // + this.rbBlock.AutoSize = true; + this.rbBlock.Location = new System.Drawing.Point(15, 42); + this.rbBlock.Name = "rbBlock"; + this.rbBlock.Size = new System.Drawing.Size(421, 17); + this.rbBlock.TabIndex = 1; + this.rbBlock.Text = "Blocked List (User can not see my online status and can not send instant messages" + + ")"; + this.rbBlock.UseVisualStyleBackColor = true; + this.rbBlock.CheckedChanged += new System.EventHandler(this.rbBlock_CheckedChanged); + // + // rbAllow + // + this.rbAllow.AutoSize = true; + this.rbAllow.Checked = true; + this.rbAllow.Location = new System.Drawing.Point(15, 19); + this.rbAllow.Name = "rbAllow"; + this.rbAllow.Size = new System.Drawing.Size(352, 17); + this.rbAllow.TabIndex = 0; + this.rbAllow.TabStop = true; + this.rbAllow.Text = "Allowed List (User can see my status and can send instant messages)"; + this.rbAllow.UseVisualStyleBackColor = true; + // + // cbContactList + // + this.cbContactList.AutoSize = true; + this.cbContactList.Checked = true; + this.cbContactList.CheckState = System.Windows.Forms.CheckState.Checked; + this.cbContactList.Location = new System.Drawing.Point(30, 125); + this.cbContactList.Name = "cbContactList"; + this.cbContactList.Size = new System.Drawing.Size(169, 17); + this.cbContactList.TabIndex = 2; + this.cbContactList.Text = "Add this user to my contact list"; + this.cbContactList.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; + this.btnOK.Location = new System.Drawing.Point(302, 125); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(75, 23); + this.btnOK.TabIndex = 3; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + this.btnOK.Click += new System.EventHandler(this.btn_Click); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(381, 125); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(75, 23); + this.btnCancel.TabIndex = 4; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + this.btnCancel.Click += new System.EventHandler(this.btn_Click); + // + // ReverseAddedForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(470, 156); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.cbContactList); + this.Controls.Add(this.gbMembership); + this.Controls.Add(this.lblAdded); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ReverseAddedForm"; + this.Text = "Pending Contact {0}"; + this.gbMembership.ResumeLayout(false); + this.gbMembership.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label lblAdded; + private System.Windows.Forms.GroupBox gbMembership; + private System.Windows.Forms.RadioButton rbAllow; + private System.Windows.Forms.RadioButton rbBlock; + private System.Windows.Forms.CheckBox cbContactList; + private System.Windows.Forms.Button btnOK; + private System.Windows.Forms.Button btnCancel; + } +} \ No newline at end of file diff --git a/Example/ReverseAddedForm.cs b/Example/ReverseAddedForm.cs new file mode 100644 index 0000000..b5d1a48 --- /dev/null +++ b/Example/ReverseAddedForm.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using MSNPSharp; + +namespace MSNPSharpClient +{ + public partial class ReverseAddedForm : Form + { + public ReverseAddedForm(Contact contact) + { + InitializeComponent(); + + Text = String.Format(Text, contact.Mail); + lblAdded.Text = String.Format(lblAdded.Text, contact.Name + " (" + contact.Mail + ")"); + } + + public bool Blocked + { + get + { + return rbBlock.Checked; + } + } + + public bool AddToContactList + { + get + { + return cbContactList.Checked; + } + } + + private void rbBlock_CheckedChanged(object sender, EventArgs e) + { + if (rbBlock.Checked) + { + cbContactList.Checked = false; + } + } + + private void btn_Click(object sender, EventArgs e) + { + Close(); + } + } +} \ No newline at end of file diff --git a/Example/ReverseAddedForm.resx b/Example/ReverseAddedForm.resx new file mode 100644 index 0000000..19dc0dd --- /dev/null +++ b/Example/ReverseAddedForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Example/RtfRichTextBox.cs b/Example/RtfRichTextBox.cs new file mode 100644 index 0000000..343626e --- /dev/null +++ b/Example/RtfRichTextBox.cs @@ -0,0 +1,427 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Imaging; +using System.Data; +using System.Text; +using System.Windows.Forms; +using System.Runtime.InteropServices; + +namespace MSNPSharpClient +{ + using MSNPSharp; + + public class RtfRichTextBox : RichTextBox + { + [DllImport("gdiplus.dll")] + private static extern uint GdipEmfToWmfBits(IntPtr _hEmf, uint _bufferSize, byte[] _buffer, int _mappingMode, EmfToWmfBitsFlags _flags); + + #region .cctor + static bool hasGdiPlus = false; + static RtfRichTextBox() + { + try + { + if(!Settings.IsMono) + { + //We are in M$ Windows! + GdipEmfToWmfBits(IntPtr.Zero, 0, null, 0, 0); + hasGdiPlus = true; + } + } + catch (Exception) + { + } + } + #endregion + + + private float xDpi; + private float yDpi; + + private RtfColor textColor = RtfColor.Black; + private RtfColor highlightColor = RtfColor.White; + private Dictionary emotions = new Dictionary(); + private Dictionary rtfColor = new Dictionary(); + private Dictionary rtfFontFamily = new Dictionary(); + + public RtfRichTextBox() + { + rtfColor.Add(RtfColor.Aqua, @"\red0\green255\blue255"); + rtfColor.Add(RtfColor.Black, @"\red0\green0\blue0"); + rtfColor.Add(RtfColor.Blue, @"\red0\green0\blue255"); + rtfColor.Add(RtfColor.Fuchsia, @"\red255\green0\blue255"); + rtfColor.Add(RtfColor.Gray, @"\red128\green128\blue128"); + rtfColor.Add(RtfColor.Green, @"\red0\green128\blue0"); + rtfColor.Add(RtfColor.Lime, @"\red0\green255\blue0"); + rtfColor.Add(RtfColor.Maroon, @"\red128\green0\blue0"); + rtfColor.Add(RtfColor.Navy, @"\red0\green0\blue128"); + rtfColor.Add(RtfColor.Olive, @"\red128\green128\blue0"); + rtfColor.Add(RtfColor.Purple, @"\red128\green0\blue128"); + rtfColor.Add(RtfColor.Red, @"\red255\green0\blue0"); + rtfColor.Add(RtfColor.Silver, @"\red192\green192\blue192"); + rtfColor.Add(RtfColor.Teal, @"\red0\green128\blue128"); + rtfColor.Add(RtfColor.White, @"\red255\green255\blue255"); + rtfColor.Add(RtfColor.Yellow, @"\red255\green255\blue0"); + + rtfFontFamily.Add(FontFamily.GenericMonospace.Name, @"\fmodern"); + rtfFontFamily.Add(FontFamily.GenericSansSerif.Name, @"\fswiss"); + rtfFontFamily.Add(FontFamily.GenericSerif.Name, @"\froman"); + rtfFontFamily.Add("UNKNOWN", @"\fnil"); + + using (Graphics graphics = CreateGraphics()) + { + xDpi = graphics.DpiX; + yDpi = graphics.DpiY; + } + } + + public RtfRichTextBox(RtfColor _textColor) + : this() + { + textColor = _textColor; + } + + public RtfRichTextBox(RtfColor _textColor, RtfColor _highlightColor) + : this() + { + textColor = _textColor; + highlightColor = _highlightColor; + } + + public void AppendRtf(string _rtf) + { + Select(TextLength, 0); + SelectionColor = Color.Black; + SelectedRtf = _rtf; + } + + public void AppendTextAsRtf(string _text) + { + AppendTextAsRtf(_text, Font); + } + + public void AppendTextAsRtf(string _text, Font _font) + { + AppendTextAsRtf(_text, _font, textColor); + } + + public void AppendTextAsRtf(string _text, Font _font, RtfColor _textColor) + { + AppendTextAsRtf(_text, _font, _textColor, highlightColor); + } + + public void AppendTextAsRtf(string _text, Font _font, RtfColor _textColor, RtfColor _backColor) + { + Select(TextLength, 0); + InsertTextAsRtf(_text, _font, _textColor, _backColor); + } + + private string GetColorTable(RtfColor _textColor, RtfColor _backColor) + { + StringBuilder builder = new StringBuilder(); + builder.Append(@"{\colortbl ;"); + builder.Append(rtfColor[_textColor]); + builder.Append(";"); + builder.Append(rtfColor[_backColor]); + builder.Append(@";}\n"); + return builder.ToString(); + } + + private string GetDocumentArea(string _text, Font _font) + { + StringBuilder builder = new StringBuilder(); + builder.Append(@"\viewkind4\uc1\pard\cf1\f0\fs20"); + builder.Append(@"\highlight2"); + if (_font.Bold) + { + builder.Append(@"\b"); + } + if (_font.Italic) + { + builder.Append(@"\i"); + } + if (_font.Strikeout) + { + builder.Append(@"\strike"); + } + if (_font.Underline) + { + builder.Append(@"\ul"); + } + builder.Append(@"\f0"); + builder.Append(@"\fs"); + builder.Append((int)Math.Round((double)(2f * _font.SizeInPoints))); + builder.Append(" "); + builder.Append(_text.Replace("\n", @"\par ")); + builder.Append(@"\highlight0"); + if (_font.Bold) + { + builder.Append(@"\b0"); + } + if (_font.Italic) + { + builder.Append(@"\i0"); + } + if (_font.Strikeout) + { + builder.Append(@"\strike0"); + } + if (_font.Underline) + { + builder.Append(@"\ulnone"); + } + builder.Append(@"\f0"); + builder.Append(@"\fs20"); + builder.Append(@"\cf0\fs17}"); + return builder.ToString(); + } + + private string GetFontTable(Font _font) + { + StringBuilder builder = new StringBuilder(); + builder.Append(@"{\fonttbl{\f0"); + builder.Append(@"\"); + if (rtfFontFamily.ContainsKey(_font.FontFamily.Name)) + { + builder.Append(rtfFontFamily[_font.FontFamily.Name]); + } + else + { + builder.Append(rtfFontFamily["UNKNOWN"]); + } + builder.Append(@"\fcharset0 "); + builder.Append(_font.Name); + builder.Append(";}}"); + return builder.ToString(); + } + + private string GetImagePrefix(Image _image) + { + StringBuilder builder = new StringBuilder(); + int picw = (int)Math.Round((double)((((float)_image.Width) / xDpi) * 2540f)); + int pich = (int)Math.Round((double)((((float)_image.Height) / yDpi) * 2540f)); + int picwgoal = (int)Math.Round((double)((((float)_image.Width) / xDpi) * 1440f)); + int pichgoal = (int)Math.Round((double)((((float)_image.Height) / yDpi) * 1440f)); + builder.Append(@"{\pict\wmetafile8"); + builder.Append(@"\picw"); + builder.Append(picw); + builder.Append(@"\pich"); + builder.Append(pich); + builder.Append(@"\picwgoal"); + builder.Append(picwgoal); + builder.Append(@"\pichgoal"); + builder.Append(pichgoal); + builder.Append(" "); + return builder.ToString(); + } + + private string GetRtfImage(Image _image) + { + MemoryStream stream = null; + Graphics graphics = null; + Metafile image = null; + string ret; + try + { + stream = new MemoryStream(); + using (graphics = CreateGraphics()) + { + IntPtr hdc = graphics.GetHdc(); + image = new Metafile(stream, hdc); + graphics.ReleaseHdc(hdc); + } + using (graphics = Graphics.FromImage(image)) + { + graphics.DrawImage(_image, new Rectangle(0, 0, _image.Width, _image.Height)); + } + IntPtr henhmetafile = image.GetHenhmetafile(); + uint num = GdipEmfToWmfBits(henhmetafile, 0, null, 1, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault); + byte[] buffer = new byte[num]; + GdipEmfToWmfBits(henhmetafile, num, buffer, 1, EmfToWmfBitsFlags.EmfToWmfBitsFlagsDefault); + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < buffer.Length; i++) + { + builder.Append(string.Format("{0:X2}", buffer[i])); + } + ret = builder.ToString(); + } + finally + { + if (graphics != null) + { + graphics.Dispose(); + } + if (image != null) + { + image.Dispose(); + } + if (stream != null) + { + stream.Close(); + } + } + return ret; + } + + public void InsertEmotion() + { + if (hasGdiPlus) + { + foreach (string emoticon in emotions.Keys) + { + int start = Find(emoticon, RichTextBoxFinds.None); + if (start > -1) + { + Select(start, emoticon.Length); + InsertImage(emotions[emoticon]); + } + } + } + } + + public void InsertImage(Image _image) + { + if (hasGdiPlus) + { + StringBuilder builder = new StringBuilder(); + builder.Append(@"{\rtf1\ansi\ansicpg1252\deff0\deflang1033"); + builder.Append(GetFontTable(Font)); + builder.Append(GetImagePrefix(_image)); + builder.Append(GetRtfImage(_image)); + builder.Append(@"}"); + + SelectedRtf = builder.ToString(); + } + } + + public void InsertRtf(string _rtf) + { + SelectedRtf = _rtf; + } + + public void InsertTextAsRtf(string _text) + { + InsertTextAsRtf(_text, Font); + } + + public void InsertTextAsRtf(string _text, Font _font) + { + InsertTextAsRtf(_text, _font, textColor); + } + + public void InsertTextAsRtf(string _text, Font _font, RtfColor _textColor) + { + InsertTextAsRtf(_text, _font, _textColor, highlightColor); + } + + public void InsertTextAsRtf(string _text, Font _font, RtfColor _textColor, RtfColor _backColor) + { + StringBuilder builder = new StringBuilder(); + builder.Append(@"{\rtf1\ansi\ansicpg1252\deff0\deflang1033"); + builder.Append(GetFontTable(_font)); + builder.Append(GetColorTable(_textColor, _backColor)); + builder.Append(GetDocumentArea(_text, _font)); + + SelectedRtf = builder.ToString(); + } + + private string RemoveBadChars(string _originalRtf) + { + return _originalRtf.Replace("\0", ""); + } + + public Dictionary Emotions + { + get + { + return emotions; + } + } + + public bool HasEmotion + { + get + { + if (hasGdiPlus) + { + foreach (string emoticon in emotions.Keys) + { + if (Text.IndexOf(emoticon, StringComparison.CurrentCultureIgnoreCase) > -1) + { + return true; + } + } + } + return false; + } + } + + public RtfColor HiglightColor + { + get + { + return highlightColor; + } + set + { + highlightColor = value; + } + } + + public new string Rtf + { + get + { + return RemoveBadChars(base.Rtf); + } + set + { + base.Rtf = value; + } + } + + public RtfColor TextColor + { + get + { + return textColor; + } + set + { + textColor = value; + } + } + + [Flags] + private enum EmfToWmfBitsFlags + { + EmfToWmfBitsFlagsDefault = 0, + EmfToWmfBitsFlagsEmbedEmf = 1, + EmfToWmfBitsFlagsIncludePlaceable = 2, + EmfToWmfBitsFlagsNoXORClip = 4 + } + + public enum RtfColor + { + Black, + Maroon, + Green, + Olive, + Navy, + Purple, + Teal, + Gray, + Silver, + Red, + Lime, + Yellow, + Blue, + Fuchsia, + Aqua, + White + } + } +}; diff --git a/Example/TraceForm.Designer.cs b/Example/TraceForm.Designer.cs new file mode 100644 index 0000000..1fa1e92 --- /dev/null +++ b/Example/TraceForm.Designer.cs @@ -0,0 +1,165 @@ +namespace MSNPSharpClient +{ + partial class TraceForm + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows 窗体设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TraceForm)); + this.tsbStart = new System.Windows.Forms.ToolStripButton(); + this.tsbStop = new System.Windows.Forms.ToolStripButton(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.tsbClear = new System.Windows.Forms.ToolStripButton(); + this.toolStrip1 = new System.Windows.Forms.ToolStrip(); + this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripLabelLevel = new System.Windows.Forms.ToolStripLabel(); + this.toolStripComboBoxLevel = new System.Windows.Forms.ToolStripComboBox(); + this.rtbTrace = new System.Windows.Forms.RichTextBox(); + this.toolStrip1.SuspendLayout(); + this.SuspendLayout(); + // + // tsbStart + // + this.tsbStart.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.tsbStart.Enabled = false; + this.tsbStart.Image = ((System.Drawing.Image)(resources.GetObject("tsbStart.Image"))); + this.tsbStart.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tsbStart.Name = "tsbStart"; + this.tsbStart.Size = new System.Drawing.Size(35, 22); + this.tsbStart.Text = "Start"; + this.tsbStart.ToolTipText = "Start Tracing"; + this.tsbStart.Click += new System.EventHandler(this.tsbStart_Click); + // + // tsbStop + // + this.tsbStop.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.tsbStop.Image = ((System.Drawing.Image)(resources.GetObject("tsbStop.Image"))); + this.tsbStop.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tsbStop.Name = "tsbStop"; + this.tsbStop.Size = new System.Drawing.Size(35, 22); + this.tsbStop.Text = "Stop"; + this.tsbStop.ToolTipText = "Stop Tracing"; + this.tsbStop.Click += new System.EventHandler(this.tsbStop_Click); + // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25); + // + // tsbClear + // + this.tsbClear.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.tsbClear.Image = ((System.Drawing.Image)(resources.GetObject("tsbClear.Image"))); + this.tsbClear.ImageTransparentColor = System.Drawing.Color.Magenta; + this.tsbClear.Name = "tsbClear"; + this.tsbClear.Size = new System.Drawing.Size(38, 22); + this.tsbClear.Text = "Clear"; + this.tsbClear.ToolTipText = "Clear All"; + this.tsbClear.Click += new System.EventHandler(this.tsbClear_Click); + // + // toolStrip1 + // + this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.tsbStart, + this.tsbStop, + this.toolStripSeparator1, + this.tsbClear, + this.toolStripSeparator2, + this.toolStripLabelLevel, + this.toolStripComboBoxLevel}); + this.toolStrip1.Location = new System.Drawing.Point(0, 0); + this.toolStrip1.Name = "toolStrip1"; + this.toolStrip1.Size = new System.Drawing.Size(661, 25); + this.toolStrip1.TabIndex = 1; + this.toolStrip1.Text = "toolStrip1"; + // + // toolStripSeparator2 + // + this.toolStripSeparator2.Name = "toolStripSeparator2"; + this.toolStripSeparator2.Size = new System.Drawing.Size(6, 25); + // + // toolStripLabelLevel + // + this.toolStripLabelLevel.Name = "toolStripLabelLevel"; + this.toolStripLabelLevel.Size = new System.Drawing.Size(40, 22); + this.toolStripLabelLevel.Text = "Level: "; + // + // toolStripComboBoxLevel + // + this.toolStripComboBoxLevel.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.toolStripComboBoxLevel.Items.AddRange(new object[] { + "Verbose", + "Info", + "Warning", + "Error", + "Off"}); + this.toolStripComboBoxLevel.Name = "toolStripComboBoxLevel"; + this.toolStripComboBoxLevel.Size = new System.Drawing.Size(121, 25); + this.toolStripComboBoxLevel.SelectedIndexChanged += new System.EventHandler(this.toolStripComboBoxLevel_SelectedIndexChanged); + // + // rtbTrace + // + this.rtbTrace.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.rtbTrace.Location = new System.Drawing.Point(0, 30); + this.rtbTrace.Name = "rtbTrace"; + this.rtbTrace.Size = new System.Drawing.Size(661, 457); + this.rtbTrace.TabIndex = 0; + this.rtbTrace.Text = ""; + // + // TraceForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(661, 488); + this.Controls.Add(this.toolStrip1); + this.Controls.Add(this.rtbTrace); + this.Name = "TraceForm"; + this.Text = "TraceForm"; + this.Load += new System.EventHandler(this.TraceForm_Load); + this.toolStrip1.ResumeLayout(false); + this.toolStrip1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.ToolStripButton tsbStart; + private System.Windows.Forms.ToolStripButton tsbStop; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + private System.Windows.Forms.ToolStripButton tsbClear; + private System.Windows.Forms.ToolStrip toolStrip1; + private System.Windows.Forms.RichTextBox rtbTrace; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; + private System.Windows.Forms.ToolStripLabel toolStripLabelLevel; + private System.Windows.Forms.ToolStripComboBox toolStripComboBoxLevel; + + + } +} \ No newline at end of file diff --git a/Example/TraceForm.cs b/Example/TraceForm.cs new file mode 100644 index 0000000..bbe7cee --- /dev/null +++ b/Example/TraceForm.cs @@ -0,0 +1,291 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Threading; +using System.Windows.Forms; +using System.IO; +using System.Diagnostics; +using System.Security.Permissions; + +namespace MSNPSharpClient +{ + using MSNPSharp; + + public partial class TraceForm : Form + { + RichTextBoxTraceListener rtbTraceListener = null; + public TraceForm() + { + InitializeComponent(); + this.Icon = Properties.Resources.MSNPSharp_logo_small_ico; + rtbTraceListener = new RichTextBoxTraceListener(rtbTrace); + Trace.Listeners.Add(rtbTraceListener); + + FormClosing += new FormClosingEventHandler(TraceForm_FormClosing); + } + + void TraceForm_FormClosing(object sender, FormClosingEventArgs e) + { + rtbTraceListener.Close(); + Trace.Listeners.Remove(rtbTraceListener); + } + + private void tsbClear_Click(object sender, EventArgs e) + { + rtbTrace.Clear(); + } + + private void tsbStop_Click(object sender, EventArgs e) + { + rtbTraceListener.Stop(); + tsbStart.Enabled = true; + tsbStop.Enabled = false; + } + + private void tsbStart_Click(object sender, EventArgs e) + { + rtbTraceListener.Resume(); + tsbStart.Enabled = false; + tsbStop.Enabled = true; + } + + private void TraceForm_Load(object sender, EventArgs e) + { + toolStripComboBoxLevel.SelectedItem = "Verbose"; + } + + private void toolStripComboBoxLevel_SelectedIndexChanged(object sender, EventArgs e) + { + MSNPSharp.Settings.TraceSwitch.Level = (TraceLevel)Enum.Parse(typeof(TraceLevel), toolStripComboBoxLevel.SelectedItem.ToString()); + } + } + + + public class TraceWriter : TextWriter + { + private RichTextBox richTextBox = null; + private delegate void WriteHandler(string buffer, RichTextBox rtb); + private const int MaxBufferLen = 1024; + private StringBuilder buffer = new StringBuilder(MaxBufferLen); + private DateTime lastInputTime = DateTime.Now; + private Thread writeThread = null; + private Queue messageQueue = new Queue(MaxBufferLen); + private bool canClose = false; + private bool userClick = false; + private int selectionStart = 0; + private int selectionLength = 0; + + protected virtual void WriteBuffer() + { + StringBuilder trace = new StringBuilder(MaxBufferLen); + while (!canClose) + { + lock (messageQueue) + { + + while (messageQueue.Count > 0) + { + trace.EnsureCapacity(buffer.Length < MaxBufferLen ? MaxBufferLen : MaxBufferLen + 2); + trace.Append(messageQueue.Dequeue()); + } + } + + if (trace.Length > 0) + { + try + { + richTextBox.BeginInvoke(new WriteHandler(OutPut), new object[] { trace.ToString(), richTextBox }); + } + catch (Exception) + { + return; + } + + trace.Remove(0, trace.Length); + } + + Thread.Sleep(Settings.IsMono ? 5000 : 100); + } + } + + protected virtual void OutPut(string buffer, RichTextBox rtb) + { + if (selectionStart == rtb.Text.Length) + userClick = false; + + rtb.AppendText(buffer); + if (userClick) + { + rtb.Select(selectionStart, selectionLength); + rtb.ScrollToCaret(); + } + } + + public TraceWriter(RichTextBox outputRTB) + { + richTextBox = outputRTB; + richTextBox.Click += new EventHandler(richTextBox_Click); + richTextBox.KeyDown += new KeyEventHandler(richTextBox_KeyDown); + writeThread = new Thread(new ThreadStart(WriteBuffer)); + writeThread.Start(); + } + + void richTextBox_KeyDown(object sender, KeyEventArgs e) + { + userClick = true; + selectionStart = richTextBox.SelectionStart; + selectionLength = richTextBox.SelectionLength; + } + + void richTextBox_Click(object sender, EventArgs e) + { + userClick = true; + selectionStart = richTextBox.SelectionStart; + selectionLength = richTextBox.SelectionLength; + } + + public override void Write(char value) + { + if (richTextBox != null && buffer != null) + { + lock (messageQueue) + { + messageQueue.Enqueue(value); + } + } + } + + public override void Close() + { + canClose = true; + base.Close(); + } + + public override Encoding Encoding + { + get { return Encoding.Default; } + } + } + + [HostProtection(SecurityAction.LinkDemand, Synchronization = true)] + public class RichTextBoxTraceListener : TraceListener + { + // Fields + private TraceWriter writer = null; + private object syncObject = new object(); + private bool stop = false; + + // Methods + public RichTextBoxTraceListener() + : base() + { + } + + public RichTextBoxTraceListener(RichTextBox rtb) + : base(string.Empty) + { + writer = new TraceWriter(rtb); + } + + + public override void Close() + { + if (this.writer != null) + { + this.writer.Close(); + } + this.writer = null; + this.stop = true; + } + + private bool EnsureWriter() + { + lock (syncObject) + { + if (writer == null || stop == true) return false; + return true; + } + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + this.Close(); + } + } + + public override void Flush() + { + if (!EnsureWriter()) return; + this.writer.Flush(); + } + + private static Encoding GetEncodingWithFallback(Encoding encoding) + { + Encoding encoding2 = (Encoding)encoding.Clone(); + encoding2.EncoderFallback = EncoderFallback.ReplacementFallback; + encoding2.DecoderFallback = DecoderFallback.ReplacementFallback; + return encoding2; + } + + public override void Write (string message) + { + if (!EnsureWriter ()) + return; + if (base.NeedIndent) + { + this.WriteIndent (); + } + + if (!Settings.IsMono) + { + this.writer.Write ("[" + DateTime.Now.ToString ("u") + "] " + message); + } + } + + public override void WriteLine(string message) + { + if (!EnsureWriter()) return; + if (base.NeedIndent) + { + this.WriteIndent(); + } + this.writer.WriteLine("[" + DateTime.Now.ToString("u") + "] " + message); + base.NeedIndent = true; + } + + public void Stop() + { + lock (syncObject) + { + stop = true; + } + } + + public void Resume() + { + lock (syncObject) + { + stop = false; + } + } + + // Properties + public TraceWriter Writer + { + get + { + return this.writer; + } + set + { + this.writer = value; + } + } + } + +} \ No newline at end of file diff --git a/Example/TraceForm.resx b/Example/TraceForm.resx new file mode 100644 index 0000000..ab988b1 --- /dev/null +++ b/Example/TraceForm.resx @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAgxJREFUOE+lkvtL + U2EYx+0PEbtpFwnBKPGKiJImGP0gYhIYs1E5GF5gIxkpA00JRSmMEF0ohMh+GaRWYlqabMVcNdS2QpaI + VqiDIYhk397vA6fXhCjyhYdzeM/5fp7vczkAdeL2cwho7v/wWzT1zcN+Pwhr51uY2/y41PQaF+wzKKiZ + QvaN58g0jyLd5KEUcQbg+84P/Cm2tncQjW3j68YWIqubCC3FcOJc478BAuGoZM6zvoRnakXEruEIjhc4 + /g5gZop9c+voGAyLbQIfeBZxLL9BA1jzXvuGbWamuKh+GmmVbswE19A59FEBbmoAG7YbsLtm2mZmiml9 + cvabNDwpz6YB7LYBoMXCumkJr7LOmnnHzBQ/9X2Bo2cOibm1GsBREbAQiYmw/8lnuCeWkVzcgnZlnw1j + 3HV/wuNXK6i/9x5Hc6wawDlTXHbLJ+LZUBQPRyKwdQdxutwl1h+NLXHh5Ht1ewBHsiwawCW57HyDAfWR + dvl0uhZQ1eqX8aVc7EKLqrum651ATLf9OJx5XQM4KmY0xPzZ0hFAiQJnXB0WwME0E3IsL5B17ZlADqWb + NYDrOepdlcysmTWWOrxqbceRWtaLk0VO1XW72D5Vckd2gMBfq8zdpmUG62NJvKM4+XyziDk24xmfWoGE + s1c0gHPmbrPTpHNJKOCo2G1mZs20zcwUJ5yp1AB5+8/zEwgF5GMVDxh4AAAAAElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAgxJREFUOE+lkvtL + U2EYx+0PEbtpFwnBKPGKiJImGP0gYhIYs1E5GF5gIxkpA00JRSmMEF0ohMh+GaRWYlqabMVcNdS2QpaI + VqiDIYhk397vA6fXhCjyhYdzeM/5fp7vczkAdeL2cwho7v/wWzT1zcN+Pwhr51uY2/y41PQaF+wzKKiZ + QvaN58g0jyLd5KEUcQbg+84P/Cm2tncQjW3j68YWIqubCC3FcOJc478BAuGoZM6zvoRnakXEruEIjhc4 + /g5gZop9c+voGAyLbQIfeBZxLL9BA1jzXvuGbWamuKh+GmmVbswE19A59FEBbmoAG7YbsLtm2mZmiml9 + cvabNDwpz6YB7LYBoMXCumkJr7LOmnnHzBQ/9X2Bo2cOibm1GsBREbAQiYmw/8lnuCeWkVzcgnZlnw1j + 3HV/wuNXK6i/9x5Hc6wawDlTXHbLJ+LZUBQPRyKwdQdxutwl1h+NLXHh5Ht1ewBHsiwawCW57HyDAfWR + dvl0uhZQ1eqX8aVc7EKLqrum651ATLf9OJx5XQM4KmY0xPzZ0hFAiQJnXB0WwME0E3IsL5B17ZlADqWb + NYDrOepdlcysmTWWOrxqbceRWtaLk0VO1XW72D5Vckd2gMBfq8zdpmUG62NJvKM4+XyziDk24xmfWoGE + s1c0gHPmbrPTpHNJKOCo2G1mZs20zcwUJ5yp1AB5+8/zEwgF5GMVDxh4AAAAAElFTkSuQmCC + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAgxJREFUOE+lkvtL + U2EYx+0PEbtpFwnBKPGKiJImGP0gYhIYs1E5GF5gIxkpA00JRSmMEF0ohMh+GaRWYlqabMVcNdS2QpaI + VqiDIYhk397vA6fXhCjyhYdzeM/5fp7vczkAdeL2cwho7v/wWzT1zcN+Pwhr51uY2/y41PQaF+wzKKiZ + QvaN58g0jyLd5KEUcQbg+84P/Cm2tncQjW3j68YWIqubCC3FcOJc478BAuGoZM6zvoRnakXEruEIjhc4 + /g5gZop9c+voGAyLbQIfeBZxLL9BA1jzXvuGbWamuKh+GmmVbswE19A59FEBbmoAG7YbsLtm2mZmiml9 + cvabNDwpz6YB7LYBoMXCumkJr7LOmnnHzBQ/9X2Bo2cOibm1GsBREbAQiYmw/8lnuCeWkVzcgnZlnw1j + 3HV/wuNXK6i/9x5Hc6wawDlTXHbLJ+LZUBQPRyKwdQdxutwl1h+NLXHh5Ht1ewBHsiwawCW57HyDAfWR + dvl0uhZQ1eqX8aVc7EKLqrum651ATLf9OJx5XQM4KmY0xPzZ0hFAiQJnXB0WwME0E3IsL5B17ZlADqWb + NYDrOepdlcysmTWWOrxqbceRWtaLk0VO1XW72D5Vckd2gMBfq8zdpmUG62NJvKM4+XyziDk24xmfWoGE + s1c0gHPmbrPTpHNJKOCo2G1mZs20zcwUJ5yp1AB5+8/zEwgF5GMVDxh4AAAAAElFTkSuQmCC + + + + 17, 17 + + \ No newline at end of file diff --git a/MSNPSharp.sln b/MSNPSharp.sln new file mode 100644 index 0000000..2e660ca --- /dev/null +++ b/MSNPSharp.sln @@ -0,0 +1,60 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotMSNClient", "Example\DotMSNClient.csproj", "{BDF3E472-EFE8-44D6-AFB6-062DD929D56F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProxyServer", "ProxyServer\ProxyServer.csproj", "{EB773C85-DDF7-4031-A993-102B9C8ED02C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSNPSharp", "MSNPSharp\MSNPSharp.csproj", "{97CB2DC7-2FE8-4AF5-84D0-6B9872A5E960}" +EndProject +Global + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = MSNPSharp.vsmdi + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BDF3E472-EFE8-44D6-AFB6-062DD929D56F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BDF3E472-EFE8-44D6-AFB6-062DD929D56F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BDF3E472-EFE8-44D6-AFB6-062DD929D56F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {BDF3E472-EFE8-44D6-AFB6-062DD929D56F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {BDF3E472-EFE8-44D6-AFB6-062DD929D56F}.Debug|Win32.ActiveCfg = Debug|Any CPU + {BDF3E472-EFE8-44D6-AFB6-062DD929D56F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BDF3E472-EFE8-44D6-AFB6-062DD929D56F}.Release|Any CPU.Build.0 = Release|Any CPU + {BDF3E472-EFE8-44D6-AFB6-062DD929D56F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {BDF3E472-EFE8-44D6-AFB6-062DD929D56F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {BDF3E472-EFE8-44D6-AFB6-062DD929D56F}.Release|Win32.ActiveCfg = Release|Any CPU + {EB773C85-DDF7-4031-A993-102B9C8ED02C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EB773C85-DDF7-4031-A993-102B9C8ED02C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EB773C85-DDF7-4031-A993-102B9C8ED02C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {EB773C85-DDF7-4031-A993-102B9C8ED02C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {EB773C85-DDF7-4031-A993-102B9C8ED02C}.Debug|Win32.ActiveCfg = Debug|Any CPU + {EB773C85-DDF7-4031-A993-102B9C8ED02C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EB773C85-DDF7-4031-A993-102B9C8ED02C}.Release|Any CPU.Build.0 = Release|Any CPU + {EB773C85-DDF7-4031-A993-102B9C8ED02C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {EB773C85-DDF7-4031-A993-102B9C8ED02C}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {EB773C85-DDF7-4031-A993-102B9C8ED02C}.Release|Win32.ActiveCfg = Release|Any CPU + {97CB2DC7-2FE8-4AF5-84D0-6B9872A5E960}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {97CB2DC7-2FE8-4AF5-84D0-6B9872A5E960}.Debug|Any CPU.Build.0 = Debug|Any CPU + {97CB2DC7-2FE8-4AF5-84D0-6B9872A5E960}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {97CB2DC7-2FE8-4AF5-84D0-6B9872A5E960}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {97CB2DC7-2FE8-4AF5-84D0-6B9872A5E960}.Debug|Win32.ActiveCfg = Debug|Any CPU + {97CB2DC7-2FE8-4AF5-84D0-6B9872A5E960}.Release|Any CPU.ActiveCfg = Release|Any CPU + {97CB2DC7-2FE8-4AF5-84D0-6B9872A5E960}.Release|Any CPU.Build.0 = Release|Any CPU + {97CB2DC7-2FE8-4AF5-84D0-6B9872A5E960}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {97CB2DC7-2FE8-4AF5-84D0-6B9872A5E960}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {97CB2DC7-2FE8-4AF5-84D0-6B9872A5E960}.Release|Win32.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = Example\DotMSNClient.csproj + EndGlobalSection +EndGlobal diff --git a/MSNPSharp/Circle.Obsolete.cs b/MSNPSharp/Circle.Obsolete.cs new file mode 100644 index 0000000..72306f6 --- /dev/null +++ b/MSNPSharp/Circle.Obsolete.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Text; +using MSNPSharp.MSNWS.MSNABSharingService; + +namespace MSNPSharp +{ + public partial class Circle + { + private ContactType hiddenRepresentative = null; + + /// + /// Circle constructor + /// + /// The "Me Contact" in the addressbook. + /// + /// + /// + [Obsolete("No hidden representative is needed anymore.", true)] + public Circle(ContactType me, ContactType hidden, CircleInverseInfoType circleInfo, NSMessageHandler handler) + : base(circleInfo.Content.Handle.Id.ToLowerInvariant(), circleInfo.Content.Handle.Id.ToLowerInvariant() + "@" + circleInfo.Content.Info.HostedDomain.ToLowerInvariant(), ClientType.CircleMember, me.contactInfo.CID, handler) + { + hostDomain = circleInfo.Content.Info.HostedDomain.ToLowerInvariant(); + hiddenRepresentative = hidden; + + CircleRole = (CirclePersonalMembershipRole)Enum.Parse(typeof(CirclePersonalMembershipRole), circleInfo.PersonalInfo.MembershipInfo.CirclePersonalMembership.Role); + + SetName(circleInfo.Content.Info.DisplayName); + SetNickName(Name); + + meContact = me; + + if (hidden != null) + { + Guid = new Guid(hidden.contactId); + + if (hidden.contactInfo != null && hidden.contactInfo.CIDSpecified) + CID = hidden.contactInfo.CID; + } + + contactList = new ContactList(AddressBookId, new Owner(AddressBookId, me.contactInfo.passportName, me.contactInfo.CID, NSMessageHandler), NSMessageHandler); + Initialize(); + } + } +} diff --git a/MSNPSharp/Circle.cs b/MSNPSharp/Circle.cs new file mode 100644 index 0000000..a853e6c --- /dev/null +++ b/MSNPSharp/Circle.cs @@ -0,0 +1,438 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; +using MSNPSharp.MSNWS.MSNABSharingService; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + /// + /// A new type of group introduces with WLM2009. + /// + [Serializable()] + public partial class Circle : Contact + { + private ContactList contactList = null; + private string hostDomain = CircleString.DefaultHostDomain; + private long segmentCounter = 0; + + private ContactType meContact = null; + + private ABFindContactsPagedResultTypeAB abinfo = null; + + + public string HostDomain + { + get { return hostDomain; } + } + + public ContactList ContactList + { + get + { + return contactList; + } + } + + /// + /// The last change time of circle's addressbook. + /// + public string LastChanged + { + get + { + if (abinfo == null) + return WebServiceConstants.ZeroTime; + + return abinfo.lastChange; + } + } + + /// + /// Circle constructor + /// + /// The "Me Contact" in the addressbook. + /// + /// + public Circle(ContactType me, CircleInverseInfoType circleInfo, NSMessageHandler handler) + : base(circleInfo.Content.Handle.Id.ToLowerInvariant(), circleInfo.Content.Handle.Id.ToLowerInvariant() + "@" + circleInfo.Content.Info.HostedDomain.ToLowerInvariant(), ClientType.CircleMember, me.contactInfo.CID, handler) + { + hostDomain = circleInfo.Content.Info.HostedDomain.ToLowerInvariant(); + + CircleRole = (CirclePersonalMembershipRole)Enum.Parse(typeof(CirclePersonalMembershipRole), circleInfo.PersonalInfo.MembershipInfo.CirclePersonalMembership.Role); + + SetName(circleInfo.Content.Info.DisplayName); + SetNickName(Name); + + meContact = me; + + CID = 0; + + contactList = new ContactList(AddressBookId, new Owner(AddressBookId, me.contactInfo.passportName, me.contactInfo.CID, NSMessageHandler), NSMessageHandler); + Initialize(); + } + + private void CheckValidation() + { + if (NSMessageHandler == null) + throw new MSNPSharpException("NSMessagehandler is null"); + if (!NSMessageHandler.IsSignedIn) + throw new InvalidOperationException("Cannot send a message without signning in to the server. Please sign in first."); + + if (NSMessageHandler.ContactList.Owner.Status == PresenceStatus.Hidden) + throw new InvalidOperationException("Cannot send a message when you are in 'Hidden' status."); + } + + private string ConstructSDGScheme() + { + string from = ((int)NSMessageHandler.ContactList.Owner.ClientType).ToString() + ":" + + NSMessageHandler.ContactList.Owner.Mail + + ";epid=" + NSMessageHandler.ContactList.Owner.MachineGuid.ToString("B").ToLowerInvariant(); + + + string to = ((int)ClientType).ToString() + ":" + Mail + ";path=IM"; + + string routingInfo = CircleString.RoutingScheme.Replace(CircleString.ToReplacementTag, to); + routingInfo = routingInfo.Replace(CircleString.FromReplacementTag, from); + + string reliabilityInfo = CircleString.ReliabilityScheme.Replace(CircleString.StreamReplacementTag, "0"); + reliabilityInfo = reliabilityInfo.Replace(CircleString.SegmentReplacementTag, IncreaseSegmentCounter().ToString()); + + string putCommandString = CircleString.CircleMessageScheme; + putCommandString = putCommandString.Replace(CircleString.RoutingSchemeReplacementTag, routingInfo); + putCommandString = putCommandString.Replace(CircleString.ReliabilitySchemeReplacementTag, reliabilityInfo); + + return putCommandString; + } + + /// + /// Send nudge to all members in this circle. + /// + /// NSMessageHandler is null + /// Not sign in to the server, or in status. + public void SendNudge() + { + CheckValidation(); + string scheme = ConstructSDGScheme(); + + scheme = scheme.Replace(CircleString.MessageSchemeReplacementTag, CircleString.NudgeMessageScheme); + + NSPayLoadMessage nspayload = new NSPayLoadMessage("SDG", scheme); + NSMessageHandler.MessageProcessor.SendMessage(nspayload); + } + + /// + /// Send a text message to all members in this circle. + /// + /// + /// NSMessageHandler is null + /// Not sign in to the server, or in status. + public void SendMessage(TextMessage textMessage) + { + CheckValidation(); + + string scheme = ConstructSDGScheme(); + + textMessage.PrepareMessage(); + + string content = MimeHeaderStrings.X_MMS_IM_Format + ": " + textMessage.GetStyleString() + "\r\n\r\n" + textMessage.Text; + string textMessageScheme = CircleString.TextMessageScheme.Replace(CircleString.TextMessageContentReplacementTag, content); + textMessageScheme = textMessageScheme.Replace(CircleString.ContentLengthReplacementTag, textMessage.Text.Length.ToString()); + + scheme = scheme.Replace(CircleString.MessageSchemeReplacementTag, textMessageScheme); + + NSPayLoadMessage nspayload = new NSPayLoadMessage("SDG", scheme); + NSMessageHandler.MessageProcessor.SendMessage(nspayload); + + } + + /// + /// Send a typing message indicates that you are typing to all members in this circle. + /// + /// NSMessageHandler is null + /// Not sign in to the server, or in status. + public void SendTypingMessage() + { + CheckValidation(); + string scheme = ConstructSDGScheme(); + + string typingScheme = CircleString.TypingMessageScheme.Replace(CircleString.OwnerReplacementTag, NSMessageHandler.ContactList.Owner.Mail); + scheme = scheme.Replace(CircleString.MessageSchemeReplacementTag, typingScheme); + + NSPayLoadMessage nspayload = new NSPayLoadMessage("SDG", scheme); + NSMessageHandler.MessageProcessor.SendMessage(nspayload); + } + + internal long IncreaseSegmentCounter() + { + return segmentCounter++; + } + + /// + /// Get a specific contact from circle's contact list by the information provided. + /// + /// The contact information + /// The parse option for the account parameter + /// + internal Contact GetMember(string account, AccountParseOption option) + { + string lowerAccount = account.ToLowerInvariant(); + try + { + switch (option) + { + case AccountParseOption.ParseAsClientTypeAndAccount: + { + string[] typeAccount = lowerAccount.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); + if (typeAccount.Length >= 2) + { + ClientType type = (ClientType)(int.Parse(typeAccount[0])); + string mail = typeAccount[1]; + if (HasMember(mail, type)) + { + return ContactList.GetContact(mail, type); + } + + return null; + + } + } + break; + case AccountParseOption.ParseAsFullCircleAccount: + { + string[] sp = lowerAccount.Split(new string[] { CircleString.ViaCircleGroupSplitter }, StringSplitOptions.RemoveEmptyEntries); + if (sp.Length < 2) + { + return null; + } + + string[] idDomain = sp[1].Split(new char[] { '@' }, StringSplitOptions.RemoveEmptyEntries); + if (idDomain.Length < 2) + return null; + string[] typeAccount = sp[0].Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); + if (typeAccount.Length < 2) + return null; + Guid abid = new Guid(idDomain[0]); + if (abid != AddressBookId || idDomain[1].ToLowerInvariant() != HostDomain) //Is it the correct circle selected? + return null; + + ClientType type = (ClientType)(int.Parse(typeAccount[0])); + string mail = typeAccount[1]; + if (HasMember(mail, type)) + { + return ContactList.GetContact(mail, type); + } + + return null; + } + + } + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "Get contact from circle error: account: " + account + + " in " + ToString() + "\r\nError Message: " + ex.Message); + } + + return null; + } + + /// + /// Remove a specific contact from circle's contact list by the information provided. + /// + /// The contact information + /// The parse option for the account parameter + /// + internal bool RemoveMember(string account, AccountParseOption option) + { + string lowerAccount = account.ToLowerInvariant(); + try + { + switch (option) + { + case AccountParseOption.ParseAsClientTypeAndAccount: + { + string[] typeAccount = lowerAccount.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); + if (typeAccount.Length >= 2) + { + ClientType type = (ClientType)(int.Parse(typeAccount[0])); + string mail = typeAccount[1]; + if (HasMember(mail, type)) + { + ContactList.Remove(account, type); + return true; + } + + return false; + + } + } + break; + case AccountParseOption.ParseAsFullCircleAccount: + { + string[] sp = lowerAccount.Split(new string[] { CircleString.ViaCircleGroupSplitter }, StringSplitOptions.RemoveEmptyEntries); + if (sp.Length < 2) + { + return false; + } + + string[] idDomain = sp[1].Split(new char[] { '@' }, StringSplitOptions.RemoveEmptyEntries); + if (idDomain.Length < 2) + return false; + string[] typeAccount = sp[0].Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); + if (typeAccount.Length < 2) + return false; + Guid abid = new Guid(idDomain[0]); + if (abid != AddressBookId || idDomain[1].ToLowerInvariant() != HostDomain) //Is it the correct circle selected? + return false; + + ClientType type = (ClientType)(int.Parse(typeAccount[0])); + string mail = typeAccount[1]; + if (HasMember(mail, type)) + { + ContactList.Remove(account, type); + return true; + } + + return false; + } + + } + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "Remove contact from circle error: account: " + account + + " in " + ToString() + "\r\nError Message: " + ex.Message); + } + + return false; + } + + + /// + /// Check whether a specific contact exists in circle's contact list by the information provided. + /// + /// The contact information + /// The parse option for the account parameter + /// + internal bool HasMember(string account, AccountParseOption option) + { + string lowerAccount = account.ToLowerInvariant(); + try + { + switch (option) + { + case AccountParseOption.ParseAsClientTypeAndAccount: + { + string[] typeAccount = lowerAccount.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); + if (typeAccount.Length >= 2) + { + ClientType type = (ClientType)(int.Parse(typeAccount[0])); + string mail = typeAccount[1]; + return HasMember(mail, type); + } + } + break; + case AccountParseOption.ParseAsFullCircleAccount: + { + string[] sp = lowerAccount.Split(new string[] { CircleString.ViaCircleGroupSplitter }, StringSplitOptions.RemoveEmptyEntries); + if (sp.Length < 2) + { + return false; + } + + string[] idDomain = sp[1].Split(new char[] { '@' }, StringSplitOptions.RemoveEmptyEntries); + if (idDomain.Length < 2) + return false; + string[] typeAccount = sp[0].Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); + if (typeAccount.Length < 2) + return false; + Guid abid = new Guid(idDomain[0]); + if (abid != AddressBookId || idDomain[1].ToLowerInvariant() != HostDomain) //Is it the correct circle selected? + return false; + + ClientType type = (ClientType)(int.Parse(typeAccount[0])); + string mail = typeAccount[1]; + return HasMember(mail, type); + } + + } + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "Verifying membership error: account: " + account + + " in " + ToString() + "\r\nError Message: " + ex.Message); + } + + return false; + } + + + internal bool HasMember(string account, ClientType type) + { + lock (ContactList) + return ContactList.HasContact(account, type); + } + + internal bool HasMember(Guid contactId) + { + lock (ContactList) + return (ContactList.GetContactByGuid(contactId) != null); + + } + + internal bool HasMember(long CID) + { + lock (ContactList) + return (ContactList.GetContactByCID(CID) != null); + } + + internal void SetAddressBookInfo(ABFindContactsPagedResultTypeAB abInfo) + { + abinfo = abInfo; + } + + #region Protected + protected virtual void Initialize() + { + ContactType = MessengerContactType.Circle; + Lists = MSNLists.AllowedList | MSNLists.ForwardList; + } + + #endregion + } +} diff --git a/MSNPSharp/CircleInviter.cs b/MSNPSharp/CircleInviter.cs new file mode 100644 index 0000000..073cab6 --- /dev/null +++ b/MSNPSharp/CircleInviter.cs @@ -0,0 +1,76 @@ +#region +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice, Andy Phan. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + + +using System; +using System.Collections.Generic; +using System.Text; +using MSNPSharp.MSNWS.MSNABSharingService; + +namespace MSNPSharp +{ + /// + /// The who send a join contact invitation. + /// + [Obsolete("Inviter is no more supported by Microsoft.")] + [Serializable()] + public class CircleInviter : Contact + { + private string message = string.Empty; + + /// + /// Invitation message send via the email. + /// + public string Message + { + get + { + return message; + } + } + + + internal CircleInviter(ContactType inviter, string inviterMessage) + : base(WebServiceConstants.MessengerIndividualAddressBookId, inviter.contactInfo.passportName, ClientType.PassportMember, inviter.contactInfo.CID, null) + { + if (inviterMessage != null) + message = inviterMessage; + } + + internal CircleInviter(string inviterEmail, string inviterName, string inviterMessage) + : base(WebServiceConstants.MessengerIndividualAddressBookId, inviterEmail, ClientType.PassportMember, 0, null) + { + if (inviterMessage != null) + message = inviterMessage; + } + } +} diff --git a/MSNPSharp/CircleList.cs b/MSNPSharp/CircleList.cs new file mode 100644 index 0000000..1ff7b08 --- /dev/null +++ b/MSNPSharp/CircleList.cs @@ -0,0 +1,168 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections; +using System.Threading; + +namespace MSNPSharp +{ + [Serializable()] + public class CircleList : IEnumerable + { + private Dictionary list = new Dictionary(); + + [NonSerialized] + private NSMessageHandler nsMessageHandler = null; + + [NonSerialized] + private object syncRoot; + + public object SyncRoot + { + get + { + if (syncRoot == null) + { + object newobj = new object(); + Interlocked.CompareExchange(ref syncRoot, newobj, null); + } + return syncRoot; + } + } + + internal bool AddCircle(Circle circle) + { + if (this[circle.Mail] == null) + { + lock (SyncRoot) + list.Add(circle.Mail, circle); + return true; + } + else + { + lock (SyncRoot) + { + circle.Lists = list[circle.Mail].Lists; + list[circle.Mail] = circle; + } + } + + return false; + } + + /// + /// Remove a circle from circle list. + /// + /// + internal void RemoveCircle(Circle circle) + { + lock (SyncRoot) + { + list.Remove(circle.Mail); + } + } + + /// + /// Remove a circle from circle list, by providing addressbook Id and Host Domain. + /// + /// The addressbook Id for circle's addressbook page. + /// The host domain of a circle. + internal void RemoveCircle(Guid abId, string hostDomain) + { + lock (SyncRoot) + { + string identifier = abId.ToString().ToLowerInvariant() + "@" + hostDomain.ToLowerInvariant(); + list.Remove(identifier); + } + } + + internal CircleList(NSMessageHandler handler) + { + nsMessageHandler = handler; + } + + + /// + /// Find by circle Id and host domain if circle not found, return null. + /// + /// Circle id + /// Circle host domain. + /// + public Circle this[Guid abId, string hostDomain] + { + get + { + string identifier = abId.ToString().ToLowerInvariant() + "@" + hostDomain.ToLowerInvariant(); + if (list.ContainsKey(identifier)) + return list[identifier]; + + return null; + } + } + + /// + /// Find by circle Id and host domain, if circle not found, return null. + /// + /// Via Id: guid@hostdomain + /// + public Circle this[string idAndHostDomain] + { + get + { + string identifier = idAndHostDomain.ToLowerInvariant(); + if (list.ContainsKey(identifier)) + return list[identifier]; + + return null; + } + } + + public IEnumerator GetEnumerator() + { + return list.Values.GetEnumerator(); + } + + public void Clear() + { + lock (SyncRoot) + list.Clear(); + } + + public int Count + { + get { return list.Count; } + } + } +} diff --git a/MSNPSharp/ClassDiagram1.cd b/MSNPSharp/ClassDiagram1.cd new file mode 100644 index 0000000..19c6950 --- /dev/null +++ b/MSNPSharp/ClassDiagram1.cd @@ -0,0 +1,923 @@ + + + + + + + Configuration.cs + AABAAAAAAAAAAAAAAAAAAAAAAAAgAAoAAABAIAAACAA= + + + + + + ConnectivityException.cs + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + + + + ConnectivitySettings.cs + AAQAAACEAAAAoAAEACAAAgAACAIACAwCAAgEAgAAAAA= + + + + + + Contact.cs + AAAAAAAAAAAAAAAACAAAAAgIAAAACAAAAAAAAAAAAAA= + + + + + + Contact.cs + AAAAAAAAAAAAAAAACAAAAAgAAAAAAAAAAAAAAAAAAAA= + + + + + + Contact.cs + AAAAAAAAAAAAAAAAAAAAAAAIAAAACAAAAAAAAAAAAAA= + + + + + + Contact.cs + UFVJQQQEoQJFgSQgwLFkVFSFQUxOFekEUgDAQRFAAmU= + + + + + + ContactGroup.cs + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQ= + + + + + + ContactGroup.cs + EAAAAAAAAAAAAAAAgAAAABQEAAAEBIAAEAAAQBAAAAA= + + + + + + ContactGroupList.cs + AAIAAgAAAAAAABAACAAABAAAAAAgAAAAEAAAAABAAAg= + + + + + + + ContactList.cs + AAAAAAAgACAACAAQKAAAFAAAAAABAAAAgoACIAAIIAI= + + + + + + Conversation.cs + BEIQRCKCFZVEgCWg0EACpBMQBg0FwBSxg4QGIAUUYQA= + + + + + + Credentials.cs + AAAAAAAgAAIAAAAAAAAAAAAgAAAAAAACAAAAQgAAAEA= + + + + + + DisplayImage.cs + AAAAAAAAAAAAAAAAAAAAAAAAEAAACBAAEAAAAAAAAAA= + + + + + + Emoticon.cs + AAAAAAAAAAAAAAAAAAAEAAAABAAAAAAAAAAAAAAAAAA= + + + + + + EmoticonMessage.cs + AACAAAAAACAACCAkAAAABAAAAAQAAAAAAAAAAAAAAAA= + + + + + + EventArgs.cs + AAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAA= + + + + + + EventArgs.cs + AAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAIACA= + + + + + + EventArgs.cs + AAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAIIAA= + + + + + + EventArgs.cs + AAgAAAAAAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAIAAA= + + + + + + MailEventArgs.cs + SAAAAUgAEAEgAAAAIAAAAAAAEAAAAAAAAAAAAAAAAAA= + + + + + + MailEventArgs.cs + AAgAAAAAAAAAQAAABAAAAAQABAAAAAAAAAAEAAAIAAA= + + + + + + MailEventArgs.cs + AgACAQIAAAEARAAAAIQAAACEAAAABAAAAAAEAAAAAgA= + + + + + + Messenger.cs + AAAAAAAAAAAAAAAAAAAAAAAAAAAQQAIAAAAAAAAgAAA= + + + + + + Messenger.cs + ECRAAACAAAABQAAIAAAAgIAAAEAEKEgAHECQAlACAgA= + + + + + + MobileMessage.cs + AACAAAAgAAAAKCAEACAAAAAgAAAEAAAIBAAACAAAAAA= + + + + + + MSNObject.cs + AAEIAEAABgVAgoQEgIIAQAIKBAARAIAAEISAAgAABiI= + + + + + + MSNObject.cs + AAIAAAAAAACAABBAAAAAFAQABABAAAAAAAAAAAAAICA= + + + + + + + MSNPSharpException.cs + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + + + + EventArgs.cs + AAAAAAAAAAAAAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAA= + + + + + + EventArgs.cs + AAAAAAAAAgAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAA= + + + + + + EventArgs.cs + AAABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAA= + + + + + + EventArgs.cs + AAAAAAAAAAAAAAAACQAAAAkAAAAAAAAAAAAAAAAAAAA= + + + + + + EventArgs.cs + AAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAA= + + + + + + NSMessageHandler.cs + PAjnFUTGC1CprQGioUBgIigmEHAEXPRCnELxJspflPU= + + + + + + + NSMessageProcessor.cs + AAQAAAAgCAAAAAAAACAAAIAoAAAAAAAAAAAAAAAAAgA= + + + + + + Owner.cs + gAFAAHDFIABITGWAIMwNoSwBKKdIdWkGBOABIYhAQSE= + + + + + + PersonalMessage.cs + ACACAAAAAAAAUAgEAEAYCAAAQAqAAAIAAQAAIAAwAAA= + + + + + + QRYFactory.cs + AAAAARAAAAAAAAAAAACAAEAIAAAAAAAAAAAAAAAAgAA= + + + + + + SBMessageHandler.cs + AAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + + + + SBMessageHandler.cs + AAAQAAAAEAAAAAAAAAAAAAQAAAAEAAABACAAQQAgAEA= + + + + + + SBMessageHandler.cs + FEABzQZCGIBQCABusUggIDGaFoAAeBSQHAAAIBGE4BA= + + + + + + + SBMessageProcessor.cs + AAQAAAAgCAAAAAAAACACAIAoAAAAAAAAAAAAAAAAAgA= + + + + + + StrDictionary.cs + AAAAAIAAAAAAAAQAAAAEAAAAAAAAAAAAAAAgAAAAAAA= + + + + + + StrDictionary.cs + AAICAAAAAAAEABAACAAAAAAAAAAAAAAAAAAAAABAAAA= + + + + + + + TextMessage.cs + IAKAAAAAQAAACCAEAAQAAAAMABABCACYAAQAiAAGABA= + + + + + + + UnauthorizedException.cs + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + + + + + + + + + + + + Wink.cs + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + + + + Core\Factory.cs + ECAAIAAAABAFABAICAEACAhAgQAFYCAgYBAABAQAAAQ= + + + + + + Core\MessagePool.cs + AAAAAAAAAAECAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAA= + + + + + + Core\MSNMessage.cs + AACAAYAgAAGgCCAMAAAABAAgAAQAAAAAAQgAAAAAAAA= + + + + + + + Core\NetworkMessage.cs + AACAAAAAQgAACiAAAIIEAAAABgAAAABAgQAAAAAAAAA= + + + + + + Core\NotificationMessage.cs + AACQkAAwAACALAgEIIAAABAAAgAEAQgIAAAABAEAAgE= + + + + + + Core\NSMessage.cs + AACAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + + + + + Core\NSMessagePool.cs + AAAAAAAAACECEAQAIFCAAAAAAAAAEgAAABIAAAAAAAA= + + + + + + + Core\SBMessage.cs + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + + + + Core\SBMessagePool.cs + AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + + + + Core\SBMSGMessage.cs + AACAQAAIAEAACAAEAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + + + + Core\SocketMessageProcessor.cs + CARgAAIBAAAAQQAAACBBQJAQQUAAIEICAAEAAgAYAkA= + + + + + + + DataTransfer\MSNSLPHandler.cs + EAgKIhAAAgIAEABAABgAIkCIACJAgAAAAAAAAAAICEA= + + + + + + DataTransfer\MSNSLPHandler.cs + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAAAAAA= + + + + + + DataTransfer\MSNSLPHandler.cs + AIAAAQDUAUEAQAFAAAgAAAAAAAAAAVAAAAEAAAAIAAA= + + + + + + DataTransfer\MSNSLPHandler.cs + CQAAgQBGECAgAAgAQBJgAIQVEAEAOCAAAFAAQ4AAgCA= + + + + + + + DataTransfer\MSNSLPMessage.cs + IgiAACIAAAAAiAAEAIAhBAoAkQAYCJgAEAgQACAIAAA= + + + + + + DataTransfer\P2PDCPool.cs + AAAAAAAAAAECAAAAAEAAAAAAAAAAAAABAAAQAAAAABA= + + + + + + DataTransfer\P2PDirectProcessor.cs + AAQAAAAAAAEAAEAAACCAAAAAgAAAAAAAAQAAAAAAAgA= + + + + + + DataTransfer\P2PHandler.cs + AAAAAAAAAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAA= + + + + + + DataTransfer\P2PHandler.cs + GAgoAABAQAQgAxkACAAgAAA0ECEAKQAAEAAAIAAIEIA= + + + + + + + DataTransfer\P2PMessage.cs + BBCgBAQAAIIgCKAGIAiAAAAIBAAAAARAACAAQAAghAQ= + + + + + + DataTransfer\P2PMessage.cs + AAAAAAAABAAAAAAEAAAAAAAAQAAAAAAAAAAAAAAAAAA= + + + + + + DataTransfer\P2PMessage.cs + AACAAAAAAAAACAAEAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + + + + DataTransfer\P2PMessage.cs + AACgAAAAAAAAAAAEAAAAAAAEAAAABAAAAAAAAAAAAAA= + + + + + + DataTransfer\P2PMessagePool.cs + AAAAAAAAAAAAAAAAAEgAAAAAAAAAAQAAAAACQAAAAAA= + + + + + + DataTransfer\P2PMessageSession.cs + S9AkKABIECQADwAECDGgIgkiUDASagBAGEACIUIAhAA= + + + + + + + DataTransfer\P2PTransferSession.cs + CBgYCYBIAKEEEQDEBDjgUDAoICAAKEBIAAEQAhAYGAM= + + + + + + + ProxySocket\AuthMethod.cs + AAAAAAQBAAAAAEAAAAAAAAIAAAAACAAgAAAAAgAAQAA= + + + + + + ProxySocket\AuthNone.cs + AAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAgAAAAAAAAAAA= + + + + + + ProxySocket\AuthUserPass.cs + AAAAAAAAAAAQAAAAAQAABQIBAAAAAAAiAAAAAAAABAA= + + + + + + ProxySocket\IAsyncProxyResult.cs + AAAAAAIAAAAABAAAAAAAECAAAAAAABAQEAACAAAAAAA= + + + + + + + ProxySocket\ProxyException.cs + AAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAA= + + + + + + ProxySocket\ProxySocket.cs + AAAQAAAEICCJAEgAAAQAIICACAQFACAGAAAARAAgAEA= + + + + + + ProxySocket\Socks4Handler.cs + AAAAABAAAAASAAAAAAAAAAABAAEEAAAAAAAAAAAAAAg= + + + + + + ProxySocket\Socks5Handler.cs + AAAAABAAAAASAAAAAEAAAQKBAAEEAAACAEAABEAQEAg= + + + + + + ProxySocket\SocksHandler.cs + AAAAABQBACAAAAAAEQAABAAACAAACEAAAAAQAgAAQAg= + + + + + + Core\YIMMessage.cs + AACAAAAAAAEAAGAAAAAABAAgBAAAAIAAAQAAAAAAAAA= + + + + + + YIMMessageHandler.cs + AAAAAABAAAAAAAAsAAAAAAECAgAAABwACAAAAAKAAAA= + + + + + + Core\IMessageHandler.cs + AAAAAABAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAA= + + + + + + Core\MessageProcessor.cs + CAAAAAAAAAAAAQAAACAAAAAAAAAAAAAAAAAAAAAAAAA= + + + + + + enums.cs + AAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAEAAAA= + + + + + + enums.cs + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACEAAAAAAAAAAI= + + + + + + enums.cs + AAAAAABABAAAAAAAAAgAEAAAAABAAAAAAAAAIAAEgFA= + + + + + + enums.cs + AAcpAoEqohACAGQAgEYgAIaHBAoURRIJAUFQACGBAJA= + + + + + + enums.cs + AAQAAAQAAAAAAAAAAAAAAAAAAAQAAAAAQAAAAAEIAAA= + + + + + + enums.cs + AAAAAAAAAAAIAAAAAgAAAAAAAAAAAAAAAAAAAAAAABA= + + + + + + enums.cs + AAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAEAAAAAAABA= + + + + + + enums.cs + AABACAAIAJNIJAIAAAAFAAGAAEBgAEAAjAAIAQkYCAA= + + + + + + enums.cs + AAAAAAAAAAAAACAAAIAAAAAAAAACAAAAAAAAAAEAAAE= + + + + + + enums.cs + QAAAAAEAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAEAAAA= + + + + + + enums.cs + AAAIAQAAABCABEACAEAAICAQABAAACAAAIAAEAIIiAA= + + + + + + MSNObject.cs + IACAAAAAEAAAAAAAAAYABAAAAABCAAFAAAAiAIAAABA= + + + + + + enums.cs + AAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAABA= + + + + + + DataTransfer\MSNSLPHandler.cs + AAAAAAAAAAAAAAAAAIAABAAAAAAEAAAAAAAAAEAAABA= + + + + + + DataTransfer\P2PMessage.cs + AgAAAAIIAgCAAAAAAAgAAAAAAAAMQACAAAAAAAAAAAA= + + + + + + ProxySocket\ProxySocket.cs + AAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAEAAAA= + + + + + + Messenger.cs + AAAAAAAgAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAA= + + + + + + NSMessageHandler.cs + EAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAA= + + + + + + NSMessageHandler.cs + AAAgAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAA= + + + + + + NSMessageHandler.cs + ABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAA= + + + + + + NSMessageHandler.cs + AAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQ= + + + + + + NSMessageHandler.cs + AAAAAAAAAAAAAAAAAAgAAAAQAAAAAAAAAAAAAAAAAAA= + + + + + + NSMessageHandler.cs + AAAAAAAACAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAA= + + + + + + NSMessageHandler.cs + AAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAIA= + + + + + + NSMessageHandler.cs + AAAAAAAAAAAAAAAAAAAAAAAQAACAAAAAAAAAAAAAAAA= + + + + + + NSMessageHandler.cs + AAAAAAAAAAAAAAAAAAAAAAAQAAAEAAAAAAAAAAAAAAA= + + + + + + NSMessageHandler.cs + AAAAAAAAAAAAAAAAAAAAAAAQAAAAAgAAAAAAAAAAAAA= + + + + + + NSMessageHandler.cs + AAAAAAAAAAAAAAAgAAAAAAAQAAAAAAAAAAAAAAAAAAA= + + + + + + SBMessageHandler.cs + AAAAAAAAAAAAAAAAAACAAAAQAAAAAAAAAAAAAAAAAAA= + + + + + + SBMessageHandler.cs + AAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAQAAAA= + + + + + + SBMessageHandler.cs + AAAAAACAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAA= + + + + + + SBMessageHandler.cs + AAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAEAAAAA= + + + + + + SBMessageHandler.cs + EAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAA= + + + + + + IMessageHandler.cs + AAAAAAAAAAAAAACAAAAAAAAQAAAAAAAAAAAAAAAAAAA= + + + + + + IMessageHandler.cs + AAAAAAAAAQAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAA= + + + + + + MessageProcessor.cs + AAAAAAAAAQAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAA= + + + + + + MSNSLPHandler.cs + AAAAAAAAAAAIAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAA= + + + + + + MSNSLPHandler.cs + AAAACAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAA= + + + + + + P2PHandler.cs + CAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAA= + + + + + + ProxySocket\SocksHandler.cs + AAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAA= + + + \ No newline at end of file diff --git a/MSNPSharp/Comparers.cs b/MSNPSharp/Comparers.cs new file mode 100644 index 0000000..74b0526 --- /dev/null +++ b/MSNPSharp/Comparers.cs @@ -0,0 +1,85 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + + +using System; +using System.Collections.Generic; +using System.Text; + +namespace MSNPSharp +{ + /// + /// A comparer which treat siblings as the same contact. + /// + /// + public class SiblingComparer : IEqualityComparer + { + #region IEqualityComparer Members + + public bool Equals(TKey x, TKey y) + { + return GetHashCode(x) == GetHashCode(y); + } + + public int GetHashCode(TKey obj) + { + if (obj is Contact) + { + return (obj as Contact).SiblingString.GetHashCode(); + } + + return obj.GetHashCode(); + } + + #endregion + } + + namespace Utilities + { + public class ConversationIDComparer : IEqualityComparer + { + #region IEqualityComparer Members + + public bool Equals(ConversationID x, ConversationID y) + { + return x == y; + } + + public int GetHashCode(ConversationID obj) + { + return obj.GetHashCode(); + } + + #endregion + } + } +} diff --git a/MSNPSharp/Configuration.cs b/MSNPSharp/Configuration.cs new file mode 100644 index 0000000..703371b --- /dev/null +++ b/MSNPSharp/Configuration.cs @@ -0,0 +1,237 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Diagnostics; + +namespace MSNPSharp +{ + using MSNPSharp.IO; + using MSNPSharp.Core; + + [Serializable] + public enum PublicPortPriority + { + None = 0, + First = 1, + Last = 9 + } + + /// + /// General configuration options. + /// + [Serializable()] + public static class Settings + { + /// + /// Defines the verbosity of the trace messages. + /// + public static TraceSwitch TraceSwitch = new TraceSwitch("MSNPSharp", "MSNPSharp switch"); + + /// + /// Ports for DC to try bind. These ports aren't firewalled by ISS. + /// + public static readonly ushort[] PublicPorts = new ushort[] + { + 80, // http + 21, // ftp + 25, // smtp + 110, // pop3 + 443, // https + 8080 // webcache + }; + + + + /// + /// Constructor. + /// + static Settings() + { + isMono = (null != Type.GetType("Mono.Runtime")); // http://www.mono-project.com/FAQ:_Technical + + TraceSwitch.Level = TraceLevel.Verbose; +#if DEBUG + serializationType = MclSerialization.Compression | MclSerialization.Cryptography; +#else + serializationType = MclSerialization.Compression; +#endif + enableGzipCompressionForWebServices = (isMono == false); + } + + private static PublicPortPriority publicPortPriority = PublicPortPriority.First; + private static string savepath = Path.GetFullPath("."); + private static bool enableGzipCompressionForWebServices; + private static MclSerialization serializationType; + private static int msnTicketsCleanupInterval = 5; + private static int msnTicketLifeTime = 20; + private static bool noSave; + private static bool isMono; + + public static PublicPortPriority PublicPortPriority + { + get + { + return publicPortPriority; + } + set + { + publicPortPriority = value; + } + } + + /// + /// Indicates whether the runtime framework is currently mono or not. + /// + public static bool IsMono + { + get + { + return isMono; + } + } + + /// + /// File serialization type when saving. + /// Compression saves spaces on disk, Encrypt protects your addressbook but eats some cpu + /// + public static MclSerialization SerializationType + { + get + { + return serializationType; + } + set + { + serializationType = value; + } + } + + /// + /// Don't save addressbook files. + /// + public static bool NoSave + { + get + { + return noSave; + } + set + { + noSave = value; + } + } + + /// + /// Save directory + /// + public static string SavePath + { + get + { + return savepath; + } + set + { + savepath = value; + } + } + + /// MSNTicket lifetime in minutes for the internal cache. Default is 20 minutes. + /// Keep small if the client will connect to the msn network for the short time. + public static int MSNTicketLifeTime + { + get + { + return msnTicketLifeTime; + } + set + { + if (value <= 0) + value = 20; + + msnTicketLifeTime = value; + } + } + + /// + /// Run clean up code for the MSNTickets in every x minutes. Default is 5 minutes. + /// + public static int MSNTicketsCleanupInterval + { + get + { + return msnTicketsCleanupInterval; + } + set + { + if (value <= 0) + value = 5; + + msnTicketsCleanupInterval = value; + } + } + + /// + /// Use Gzip compression for web services to save bandwidth. + /// + /// Don't use this if you run .net framework on mono + public static bool EnableGzipCompressionForWebServices + { + get + { + return enableGzipCompressionForWebServices; + } + set + { + enableGzipCompressionForWebServices = value; + } + } + + /// + /// Don't use compression when saving addressbook files. + /// + [Obsolete("Please use SerializationType", false)] + public static bool NoCompress + { + get + { + return (serializationType == MclSerialization.None); + } + set + { + serializationType = value ? MclSerialization.None : MclSerialization.Compression; + } + } + } +}; \ No newline at end of file diff --git a/MSNPSharp/ConnectivityException.cs b/MSNPSharp/ConnectivityException.cs new file mode 100644 index 0000000..1de5072 --- /dev/null +++ b/MSNPSharp/ConnectivityException.cs @@ -0,0 +1,83 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Runtime.Serialization; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + /// + /// Specifies an exception when a connection is setup. + /// + [Serializable()] + public class ConnectivityException : MSNPSharpException + { + /// + /// Basic constructor. + /// + public ConnectivityException() + { + } + + /// + /// Specifies a ConnectivityException. + /// + /// A textual presentation of the exception message + public ConnectivityException(string message) + : base(message) + { + } + + /// + /// Specifies a ConnectivityException which originates from another exception. + /// + /// A textual presentation of the exception message + /// The (inner)exception which caused this exception. For example a SocketException + public ConnectivityException(string message, Exception innerException) + : base(message, innerException) + { + } + + /// + /// Serialization constructor. + /// + /// + /// + protected ConnectivityException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + } +}; diff --git a/MSNPSharp/ConnectivitySettings.cs b/MSNPSharp/ConnectivitySettings.cs new file mode 100644 index 0000000..5c45ce1 --- /dev/null +++ b/MSNPSharp/ConnectivitySettings.cs @@ -0,0 +1,502 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Net; +using System.Web; +using System.Net.Security; +using System.Security.Cryptography.X509Certificates; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + public class MSNServiceCertificatePolicy : ICertificatePolicy + { + public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) + { + return true; + } + } + + /// + /// Defines the way how connections must be set up. + /// + /// + /// Via ConnectivitySettings the client can specify to which MSN server must be connected, + /// whether or not proxy servers are used for internet connections and whether + /// web proxys are used for accessing HTTP resources. The most common HTTP resource + /// is the authentication with Passport.com during the login phase. + /// + [Serializable()] + public class ConnectivitySettings + { + #region Constructors + + static ConnectivitySettings() + { + try + { + ServicePointManager.ServerCertificateValidationCallback += delegate(object sender, X509Certificate certificate, + X509Chain chain, SslPolicyErrors sslPolicyErrors) + { + return true; + }; + } + catch (Exception) + { +#pragma warning disable 0618 + ServicePointManager.CertificatePolicy = new MSNServiceCertificatePolicy(); +#pragma warning restore 0618 + } + } + + /// + /// Constructor to instantiate a ConnectivitySettings object. + /// + public ConnectivitySettings() + { + } + + /// + /// Copy constructor. + /// + /// + public ConnectivitySettings(ConnectivitySettings x) + : this(x.LocalHost, x.LocalPort, x.Host, x.Port, x.ProxyHost, x.Port, x.ProxyUsername, x.ProxyPassword, x.ProxyType, x.WebProxy) + { + } + + + /// + /// Constructs a ConnectivitySettings which uses a socks proxy in all direct TCP communications with the messenger servers. HTTP resources are accessed via the supplied WebProxy. + /// + /// Host endpoint of messenger server. Standard is msnmsgr.escargot.chat:1863 + public ConnectivitySettings(IPEndPoint remoteEndPoint) + : this(remoteEndPoint.Address.ToString(), remoteEndPoint.Port) + { + } + + /// + /// Constructs a ConnectivitySettings which uses a socks proxy in all direct TCP communications with the messenger servers. HTTP resources are accessed via the supplied WebProxy. + /// + /// Local endpoint you want to bind to. + /// Host endpoint of messenger server. Standard is msnmsgr.escargot.chat:1863 + public ConnectivitySettings(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint) + : this(localEndPoint.Address.ToString(), localEndPoint.Port, remoteEndPoint.Address.ToString(), remoteEndPoint.Port) + { + } + + + /// + /// Constructs a ConnectivitySettings with custom host and port. + /// + /// Host of messenger server. Standard is msnmsgr.escargot.chat + /// Port of messenger server. Standard is 1863 + public ConnectivitySettings(string host, int port) + : this(host, port, string.Empty, 0, string.Empty, string.Empty, ProxyType.None, null) + { + } + + /// + /// Constructs a ConnectivitySettings with custom host and port. + /// + /// The local address you want to bind to. + /// The local port you want to bind to. + /// Host of messenger server. Standard is msnmsgr.escargot.chat + /// Port of messenger server. Standard is 1863 + public ConnectivitySettings(string localHost, int localPort, string host, int port) + : this(localHost, localPort, host, port, string.Empty, 0, string.Empty, string.Empty, ProxyType.None, null) + { + } + + /// + /// Constructs a ConnectivitySettings which uses a socks proxy in all direct TCP communications with the messenger servers. HTTP resources are accessed via the supplied WebProxy. + /// + /// Host endpoint of messenger server. Standard is msnmsgr.escargot.chat:1863 + /// Webproxy to be used when accessing HTTP resources + public ConnectivitySettings(IPEndPoint remoteEndPoint, WebProxy webProxy) + : this(remoteEndPoint.Address.ToString(), remoteEndPoint.Port, webProxy) + { + } + + /// + /// Constructs a ConnectivitySettings which uses a socks proxy in all direct TCP communications with the messenger servers. HTTP resources are accessed via the supplied WebProxy. + /// + /// Local endpoint you want to bind to. + /// Host endpoint of messenger server. Standard is msnmsgr.escargot.chat:1863 + /// Webproxy to be used when accessing HTTP resources + public ConnectivitySettings(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, WebProxy webProxy) + : this(localEndPoint.Address.ToString(), localEndPoint.Port, remoteEndPoint.Address.ToString(), remoteEndPoint.Port, webProxy) + { + } + + + /// + /// Constructs a ConnectivitySettings which uses a Web proxy for all HTTP connections made. + /// + /// Host of messenger server. Standard is msnmsgr.escargot.chat + /// Port of messenger server. Standard is 1863 + /// Webproxy to be used when accessing HTTP resources + public ConnectivitySettings(string host, int port, WebProxy webProxy) + : this(host, port, string.Empty, 0, string.Empty, string.Empty, ProxyType.None, webProxy) + { + } + + /// + /// Constructs a ConnectivitySettings which uses a Web proxy for all HTTP connections made. + /// + /// The local address you want to bind to. + /// The local port you want to bind to. + /// Host of messenger server. Standard is msnmsgr.escargot.chat + /// Port of messenger server. Standard is 1863 + /// Webproxy to be used when accessing HTTP resources + public ConnectivitySettings(string localHost, int localPort, string host, int port, WebProxy webProxy) + : this(localHost, localPort, host, port, string.Empty, 0, string.Empty, string.Empty, ProxyType.None, webProxy) + { + } + + + + /// + /// Constructs a ConnectivitySettings which uses a socks proxy in all direct TCP communications with the messenger servers. HTTP resources are accessed via the supplied WebProxy. + /// + /// Host endpoint of messenger server. Standard is msnmsgr.escargot.chat:1863 + /// Host endpoint of the proxy server + /// Username, if any, used when accessing the proxyserver + /// Password, if any, used when accessing the proxyserver + /// The proxy version, Socks4 or Socks5 + public ConnectivitySettings(IPEndPoint remoteEndPoint, IPEndPoint proxyEndPoint, string proxyUsername, string proxyPassword, ProxyType proxyType) + : this(remoteEndPoint.Address.ToString(), remoteEndPoint.Port, proxyEndPoint.Address.ToString(), proxyEndPoint.Port, proxyUsername, proxyPassword, proxyType, null) + { + } + + /// + /// Constructs a ConnectivitySettings which uses a socks proxy in all direct TCP communications with the messenger servers. HTTP resources are accessed via the supplied WebProxy. + /// + /// Local endpoint you want to bind to. + /// Host endpoint of messenger server. Standard is msnmsgr.escargot.chat:1863 + /// Host endpoint of the proxy server + /// Username, if any, used when accessing the proxyserver + /// Password, if any, used when accessing the proxyserver + /// The proxy version, Socks4 or Socks5 + public ConnectivitySettings(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, IPEndPoint proxyEndPoint, string proxyUsername, string proxyPassword, ProxyType proxyType) + : this(localEndPoint, remoteEndPoint, proxyUsername, proxyPassword, proxyType, null) + { + } + + /// + /// Constructs a ConnectivitySettings which uses a proxy in all direct TCP communications with the messenger servers. This means HTTP resources for authenticating the user with Passport.com are accessed directly. + /// + /// Host of messenger server. Standard is msnmsgr.escargot.chat + /// Port of messenger server. Standard is 1863 + /// Host of the proxy server + /// Port of the proxy server + /// Username, if any, used when accessing the proxyserver + /// Password, if any, used when accessing the proxyserver + /// The proxy version, Socks4 or Socks5 + public ConnectivitySettings(string host, int port, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, ProxyType proxyType) + : this(host, port, proxyHost, proxyPort, proxyUsername, proxyPassword, proxyType, null) + { + + } + + /// + /// Constructs a ConnectivitySettings which uses a socks proxy in all direct TCP communications with the messenger servers. HTTP resources are accessed via the supplied WebProxy. + /// + /// The local address you want to bind to. + /// The local port you want to bind to. + /// Host of messenger server. Standard is msnmsgr.escargot.chat + /// Port of messenger server. Standard is 1863 + /// Host of the proxy server + /// Port of the proxy server + /// Username, if any, used when accessing the proxyserver + /// Password, if any, used when accessing the proxyserver + /// The proxy version, Socks4 or Socks5 + public ConnectivitySettings(string localHost, int localPort, string host, int port, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, ProxyType proxyType) + : this(localHost, localPort, host, port, proxyHost, proxyPort, proxyUsername, proxyPassword, proxyType, null) + { + } + + + /// + /// Constructs a ConnectivitySettings which uses a socks proxy in all direct TCP communications with the messenger servers. HTTP resources are accessed via the supplied WebProxy. + /// + /// Host endpoint of messenger server. Standard is msnmsgr.escargot.chat:1863 + /// Host endpoint of the proxy server + /// Username, if any, used when accessing the proxyserver + /// Password, if any, used when accessing the proxyserver + /// The proxy version, Socks4 or Socks5 + /// Webproxy to be used when accessing HTTP resources + public ConnectivitySettings(IPEndPoint remoteEndPoint, IPEndPoint proxyEndPoint, string proxyUsername, string proxyPassword, ProxyType proxyType, WebProxy webProxy) + : this(remoteEndPoint.Address.ToString(), remoteEndPoint.Port, proxyEndPoint.Address.ToString(), proxyEndPoint.Port, proxyUsername, proxyPassword, proxyType, webProxy) + { + } + + /// + /// Constructs a ConnectivitySettings which uses a socks proxy in all direct TCP communications with the messenger servers. HTTP resources are accessed via the supplied WebProxy. + /// + /// Local endpoint you want to bind to. + /// Host endpoint of messenger server. Standard is msnmsgr.escargot.chat:1863 + /// Host endpoint of the proxy server + /// Username, if any, used when accessing the proxyserver + /// Password, if any, used when accessing the proxyserver + /// The proxy version, Socks4 or Socks5 + /// Webproxy to be used when accessing HTTP resources + public ConnectivitySettings(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, IPEndPoint proxyEndPoint, string proxyUsername, string proxyPassword, ProxyType proxyType, WebProxy webProxy) + : this(localEndPoint.Address.ToString(), localEndPoint.Port, remoteEndPoint.Address.ToString(), remoteEndPoint.Port, proxyEndPoint.Address.ToString(), proxyEndPoint.Port, proxyUsername, proxyPassword, proxyType, webProxy) + { + } + + /// + /// Constructs a ConnectivitySettings which uses a socks proxy in all direct TCP communications with the messenger servers. HTTP resources are accessed via the supplied WebProxy. + /// + /// Host of messenger server. Standard is msnmsgr.escargot.chat + /// Port of messenger server. Standard is 1863 + /// Host of the proxy server + /// Port of the proxy server + /// Username, if any, used when accessing the proxyserver + /// Password, if any, used when accessing the proxyserver + /// The proxy version, Socks4 or Socks5 + /// Webproxy to be used when accessing HTTP resources + public ConnectivitySettings(string host, int port, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, ProxyType proxyType, WebProxy webProxy) + :this(string.Empty, 0, host, port, proxyHost, proxyPort, proxyUsername, proxyPassword, proxyType, webProxy) + { + } + + /// + /// Constructs a ConnectivitySettings which uses a socks proxy in all direct TCP communications with the messenger servers. HTTP resources are accessed via the supplied WebProxy. + /// + /// The local address you want to bind to. + /// The local port you want to bind to. + /// Host of messenger server. Standard is msnmsgr.escargot.chat + /// Port of messenger server. Standard is 1863 + /// Host of the proxy server + /// Port of the proxy server + /// Username, if any, used when accessing the proxyserver + /// Password, if any, used when accessing the proxyserver + /// The proxy version, Socks4 or Socks5 + /// Webproxy to be used when accessing HTTP resources + public ConnectivitySettings(string localHost, int localPort, string host, int port, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, ProxyType proxyType, WebProxy webProxy) + { + this.localHost = localHost; + this.localPort = localPort; + this.host = host; + this.port = port; + this.proxyHost = proxyHost; + this.proxyPort = proxyPort; + this.proxyUsername = proxyUsername; + this.proxyPassword = proxyPassword; + this.proxyType = proxyType; + this.webProxy = webProxy; + } + + #endregion + + #region Private members + + private string host = "msnmsgr.escargot.chat"; + private int port = 1863; + private string localHost = string.Empty; + private int localPort = 0; + private string proxyHost = string.Empty; + private int proxyPort = 0; + private string proxyUsername = string.Empty; + private string proxyPassword = string.Empty; + private ProxyType proxyType = ProxyType.None; + private WebProxy webProxy = null; + + #endregion + + #region Public properties + + /// + /// Hostname of the MSN server. Defaults is msnmsgr.escargot.chat + /// + public string Host + { + get + { + return host; + } + set + { + host = value; + } + } + + /// + /// Port of the MSN server. Default is 1863. + /// + public int Port + { + get + { + return port; + } + set + { + port = value; + } + } + + /// + /// The local ip you want to bind. + /// + public string LocalHost + { + get + { + return localHost; + } + set + { + localHost = value; + } + } + + /// + /// The local port you want to bind, default is 0 (which means the system will assign it automatically). + /// + public int LocalPort + { + get + { + return localPort; + } + set + { + localPort = value; + } + } + + /// + /// The host of the proxy. This must be filled in when ProxyType is set to something else than ProxyType.None. + /// + public string ProxyHost + { + get + { + return proxyHost; + } + set + { + proxyHost = value; + } + } + + /// + /// The port used to access the proxy. This must be filled in when ProxyType is set to something else than ProxyType.None. + /// + public int ProxyPort + { + get + { + return proxyPort; + } + set + { + proxyPort = value; + } + } + + /// + /// The username used when accessing the proxy. This must be filled in when ProxyType is set to something else than ProxyType.None. + /// + public string ProxyUsername + { + get + { + return proxyUsername; + } + set + { + proxyUsername = value; + } + } + + /// + /// The username used when accessing the proxy. This must be filled in when ProxyType is set to something else than ProxyType.None. + /// + public string ProxyPassword + { + get + { + return proxyPassword; + } + set + { + proxyPassword = value; + } + } + + /// + /// The ProxyType used. If ProxyType is set to something else than ProxyType.None a proxy server is used, using Socks4 or Socks 5 depending on the type. Read-only. + /// + public ProxyType ProxyType + { + get + { + return proxyType; + } + set + { + proxyType = value; + } + } + + /// + /// If this is not null a webproxy is used in all HTTP request in the library. An important HTTP request is the authentication with Passport.com. + /// + public WebProxy WebProxy + { + get + { + return webProxy; + } + set + { + webProxy = value; + } + } + + /// + /// A string that shows the current host and port. + /// + /// + public override string ToString() + { + return "{Host=" + Host + ", Port=" + Port + "}"; + } + #endregion + } +}; diff --git a/MSNPSharp/Contact.cs b/MSNPSharp/Contact.cs new file mode 100644 index 0000000..11013f8 --- /dev/null +++ b/MSNPSharp/Contact.cs @@ -0,0 +1,1380 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Net; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Diagnostics; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + using MSNPSharp.MSNWS.MSNABSharingService; + + + /// + /// User in roster list. + /// + [Serializable()] + public class Contact + { + #region Fields + + protected Guid guid = Guid.Empty; + protected Guid addressBookId = Guid.Empty; + private long cId = 0; + private string mail = string.Empty; + private string name = string.Empty; + private string nickName = string.Empty; + + private Dictionary phoneNumbers = new Dictionary(); + private string contactType = string.Empty; + private string comment = string.Empty; + private string siblingString = string.Empty; + private string hash = string.Empty; + + private bool hasSpace = false; + private bool mobileDevice = false; + private bool mobileAccess = false; + private bool isMessengerUser = false; + private bool hasInitialized = false; + + private PresenceStatus status = PresenceStatus.Offline; + private ClientType clientType = ClientType.PassportMember; + private CirclePersonalMembershipRole circleRole = CirclePersonalMembershipRole.None; + + private List contactGroups = new List(0); + private MSNLists lists = MSNLists.None; + + private DisplayImage displayImage = null; + private PersonalMessage personalMessage = null; + + + private Dictionary emoticons = new Dictionary(0); + private Dictionary siblings = new Dictionary(0); + protected Dictionary endPointData = new Dictionary(0); + + private ulong oimCount = 1; + private int adlCount = 1; + private object clientData = null; + + private List activities = new List(0); + private Uri userTile = null; + private string userTileLocation = string.Empty; + + private object syncObject = new object(); + + private NSMessageHandler nsMessageHandler = null; + + #endregion + + private Contact() + { + } + + protected internal Contact(string abId, string account, ClientType cliType, long cid, NSMessageHandler handler) + { + Initialized(new Guid(abId), account, cliType, cid, handler); + } + + protected internal Contact(Guid abId, string account, ClientType cliType, long cid, NSMessageHandler handler) + { + Initialized(abId, account, cliType, cid, handler); + } + + protected virtual void Initialized(Guid abId, string account, ClientType cliType, long cid, NSMessageHandler handler) + { + if (hasInitialized) + return; + + NSMessageHandler = handler; + addressBookId = abId; + mail = account.ToLowerInvariant(); + clientType = cliType; + cId = cid; + + SetName(account); + siblingString = ClientType.ToString() + ":" + account.ToLowerInvariant(); + hash = MakeHash(Mail, ClientType, AddressBookId); + EndPointData[Guid.Empty] = new EndPointData(account, Guid.Empty); + + if (NSMessageHandler != null) + { + NSMessageHandler.Manager.Add(this); + } + + displayImage = DisplayImage.CreateDefaultImage(Mail); + + hasInitialized = true; + } + + #region Events + /// + /// Fired when contact's display name changed. + /// + public event EventHandler ScreenNameChanged; + + public event EventHandler PersonalMessageChanged; + + /// + /// Fired after contact's display image has been changed. + /// + public event EventHandler DisplayImageChanged; + + /// + /// Fired after received contact's display image changed notification. + /// + public event EventHandler DisplayImageContextChanged; + public event EventHandler ContactGroupAdded; + public event EventHandler ContactGroupRemoved; + public event EventHandler ContactBlocked; + public event EventHandler ContactUnBlocked; + public event EventHandler ContactOnline; + public event EventHandler ContactOffline; + public event EventHandler StatusChanged; + + #endregion + + #region Contact Properties + + internal object SyncObject + { + get + { + return syncObject; + } + } + + internal string SiblingString + { + get + { + return siblingString; + } + } + + internal NSMessageHandler NSMessageHandler + { + get + { + return nsMessageHandler; + } + + set + { + nsMessageHandler = value; + } + } + + /// + /// The display image url from the webside. + /// + public Uri UserTileURL + { + get + { + return userTile; + } + + internal set + { + userTile = value; + } + } + + /// + /// The displayimage context. + /// + public string UserTileLocation + { + //I create this property because I don't want to play tricks with display image's OriginalContext and Context any more. + + get + { + return userTileLocation; + } + + internal set + { + userTileLocation = MSNObject.GetDecodeString(value); + } + } + + /// + /// Get the Guid of contact, NOT CID. + /// + public Guid Guid + { + get + { + return guid; + } + + internal set + { + guid = value; + } + } + + /// + /// The identifier of addressbook this contact belongs to. + /// + public Guid AddressBookId + { + get + { + return addressBookId; + } + } + + /// + /// Machine ID, this may be different from the endpoint id. + /// + public Guid MachineGuid + { + get + { + if (PersonalMessage != null) + { + if (PersonalMessage.MachineGuid != null) + { + if (PersonalMessage.MachineGuid != Guid.Empty) + return PersonalMessage.MachineGuid; + } + } + return Guid.Empty; + } + } + + /// + /// The contact id of contact, only PassportMembers have CID. + /// + public long CID + { + get + { + return cId; + } + internal set + { + cId = value; + } + } + + /// + /// The email account of contact. + /// + public string Mail + { + get + { + return mail; + } + } + + /// + /// The display name of contact. + /// + public virtual string Name + { + get + { + return name; + } + + set + { + throw new NotImplementedException("Must be override in subclass."); + } + } + + public string HomePhone + { + get + { + return phoneNumbers.ContainsKey(ContactPhoneTypes.ContactPhonePersonal) ? + phoneNumbers[ContactPhoneTypes.ContactPhonePersonal] : string.Empty; + } + } + + public string WorkPhone + { + get + { + return phoneNumbers.ContainsKey(ContactPhoneTypes.ContactPhoneBusiness) ? + phoneNumbers[ContactPhoneTypes.ContactPhoneBusiness] : string.Empty; + } + } + + public string MobilePhone + { + get + { + return phoneNumbers.ContainsKey(ContactPhoneTypes.ContactPhoneMobile) ? + phoneNumbers[ContactPhoneTypes.ContactPhoneMobile] : string.Empty; + } + } + + public Dictionary PhoneNumbers + { + get + { + return phoneNumbers; + } + } + + public bool MobileDevice + { + get + { + return mobileDevice; + } + } + + public bool MobileAccess + { + get + { + return mobileAccess; + } + } + + /// + /// Indicates whether this contact has MSN Space. + /// + public bool HasSpace + { + get + { + return hasSpace; + } + + internal set + { + hasSpace = value; + NSMessageHandler.ContactService.UpdateContact(this, AddressBookId, null); + } + } + + public Dictionary EndPointData + { + get + { + return endPointData; + } + } + + public bool HasSignedInWithMultipleEndPoints + { + get + { + //One for Guid.Empty added when calling the constructor, another for contact's own end point. + return EndPointData.Count > 2; + } + } + + public int PlaceCount + { + get + { + return HasSignedInWithMultipleEndPoints ? EndPointData.Count - 1 : 1; + } + } + + /// + /// The online status of contact. + /// + public virtual PresenceStatus Status + { + get + { + return status; + } + + set + { + throw new NotImplementedException("This property is real-only for base class. Must be override in subclass."); + } + } + + /// + /// Indicates whether the contact is online. + /// + public bool Online + { + get + { + return status != PresenceStatus.Offline; + } + } + + /// + /// The type of contact's email account. + /// + public ClientType ClientType + { + get + { + return clientType; + } + } + + /// + /// The role of contact in the addressbook. + /// + public string ContactType + { + get + { + return contactType; + } + internal set + { + contactType = value; + } + } + + public List ContactGroups + { + get + { + return contactGroups; + } + } + + public Dictionary Siblings + { + get + { + return siblings; + } + } + + public virtual DisplayImage DisplayImage + { + get + { + + LoadDisplayImageFromDeltas(); + return displayImage; + } + + //Calling this will not fire DisplayImageChanged event. + internal set + { + if (displayImage != value) + { + displayImage = value; + SaveDisplayImage(displayImage); + } + } + } + + public PersonalMessage PersonalMessage + { + get + { + return personalMessage; + } + } + + /// + /// Emoticons[sha] + /// + public Dictionary Emoticons + { + get + { + return emoticons; + } + } + + public List Activities + { + get + { + return activities; + } + } + + /// + /// The string representation info of contact. + /// + public virtual string Hash + { + get + { + return hash; + } + } + + public object ClientData + { + get + { + return clientData; + } + set + { + clientData = value; + } + } + + /// + /// Receive updated contact information automatically. + /// Contact details like address and phone numbers are automatically downloaded to your Address Book. + /// + public bool AutoSubscribeToUpdates + { + get + { + return (contactType == MessengerContactType.Live || contactType == MessengerContactType.LivePending); + } + set + { + if (NSMessageHandler != null && Guid != Guid.Empty && ClientType == ClientType.PassportMember) + { + if (value) + { + if (!AutoSubscribeToUpdates) + { + contactType = MessengerContactType.LivePending; + NSMessageHandler.ContactService.UpdateContact(this, AddressBookId, null); + } + } + else + { + if (contactType != MessengerContactType.Regular) + { + contactType = MessengerContactType.Regular; + NSMessageHandler.ContactService.UpdateContact(this, AddressBookId, null); + } + } + } + } + } + + /// + /// Indicates whether the contact can receive MSN message. + /// + public bool IsMessengerUser + { + get + { + return isMessengerUser; + } + + + set + { + if (NSMessageHandler != null && Guid != Guid.Empty && IsMessengerUser != value) + { + isMessengerUser = value; + NSMessageHandler.ContactService.UpdateContact(this, AddressBookId, + delegate //If you don't add this, you can't see the contact online until your next login + { + Dictionary hashlist = new Dictionary(2); + hashlist.Add(Hash, Lists ^ MSNLists.ReverseList); + string payload = ContactService.ConstructLists(hashlist, false)[0]; + NSMessageHandler.MessageProcessor.SendMessage(new NSPayLoadMessage("ADL", payload)); + }); + } + + NotifyManager(); + } + } + + + public string Comment + { + get + { + return comment; + } + set + { + if (NSMessageHandler != null && Guid != Guid.Empty && Comment != value) + { + comment = value; + NSMessageHandler.ContactService.UpdateContact(this, AddressBookId, null); + } + } + } + + /// + /// The name provide by the owner. + /// + public string NickName + { + get + { + return nickName; + } + set + { + if (NSMessageHandler != null && Guid != Guid.Empty && NickName != value) + { + nickName = value; + NSMessageHandler.ContactService.UpdateContact(this, AddressBookId, null); + } + } + } + + + /// + /// The amount of OIMs sent in a session. + /// + internal ulong OIMCount + { + get + { + return oimCount; + } + set + { + if (value < 1) + { + value = 1; + } + oimCount = value; + } + } + + /// + /// The amount of ADL commands send for this contact. + /// + internal int ADLCount + { + get { return adlCount; } + set + { + if (value < 0) + { + value = 0; + } + + adlCount = value; + } + } + + internal string LocalContactString + { + get + { + return GetLocalContactString(); + + } + } + + /// + /// The role of a contact in the addressbook. + /// + public CirclePersonalMembershipRole CircleRole + { + get + { + return circleRole; + } + + internal set + { + circleRole = value; + } + } + + #endregion + + #region List Properties + + public bool OnForwardList + { + get + { + return ((lists & MSNLists.ForwardList) == MSNLists.ForwardList); + } + set + { + if (value != OnForwardList) + { + if (value) + { + NSMessageHandler.ContactService.AddContactToList(this, MSNLists.ForwardList, null); + } + else + { + NSMessageHandler.ContactService.RemoveContactFromList(this, MSNLists.ForwardList, null); + } + } + } + } + + /// + /// Blocks/unblocks this contact. If blocked, will be placed in your BL and removed + /// from your AL; otherwise, will be removed from your BL and placed in your AL. + /// If this contact is not in ReverseList and you want to delete forever, + /// set the or to false. + /// + public bool Blocked + { + get + { + return OnBlockedList; + } + set + { + if (NSMessageHandler != null) + { + if (value) + NSMessageHandler.ContactService.BlockContact(this); + else + NSMessageHandler.ContactService.UnBlockContact(this); + } + } + } + + /// + /// Adds or removes this contact into/from your AL. + /// If this contact is not in ReverseList and you want to delete forever, + /// set this property to false. + /// + public bool OnAllowedList + { + get + { + return ((lists & MSNLists.AllowedList) == MSNLists.AllowedList); + } + set + { + if (value != OnAllowedList) + { + if (value) + { + Blocked = false; + } + else if (!OnReverseList) + { + NSMessageHandler.ContactService.RemoveContactFromList(this, MSNLists.AllowedList, null); + } + } + } + } + + /// + /// Adds or removes this contact into/from your BL. + /// If this contact is not in ReverseList and you want to delete forever, + /// set this property to false. + /// + public bool OnBlockedList + { + get + { + return ((lists & MSNLists.BlockedList) == MSNLists.BlockedList); + } + set + { + if (value != OnBlockedList) + { + if (value) + { + Blocked = true; + } + else if (!OnReverseList) + { + NSMessageHandler.ContactService.RemoveContactFromList(this, MSNLists.BlockedList, null); + } + } + } + } + + /// + /// Indicates whether the contact have you on their contact list. + /// + public bool OnReverseList + { + get + { + return ((lists & MSNLists.ReverseList) == MSNLists.ReverseList); + } + } + + /// + /// Indicates whether the contact have you on their contact list and pending your approval. + /// + public bool OnPendingList + { + get + { + return ((lists & MSNLists.PendingList) == MSNLists.PendingList); + } + set + { + if (value != OnPendingList && value == false) + { + NSMessageHandler.ContactService.RemoveContactFromList(this, MSNLists.PendingList, null); + } + } + } + + /// + /// The msn lists this contact has. + /// + public MSNLists Lists + { + get + { + return lists; + } + + protected internal set + { + lists = value; + NotifyManager(); + } + } + + #endregion + + #region Internal setters + + internal void SetComment(string note) + { + comment = note; + } + + internal void SetIsMessengerUser(bool isMessengerEnabled) + { + isMessengerUser = isMessengerEnabled; + NotifyManager(); + } + + internal void SetList(MSNLists msnLists) + { + lists = msnLists; + NotifyManager(); + } + + internal void SetMobileAccess(bool enabled) + { + mobileAccess = enabled; + } + + internal void SetMobileDevice(bool enabled) + { + mobileDevice = enabled; + } + + internal void SetName(string newName) + { + if (name != newName) + { + string oldName = name; + name = newName; + + // notify all of our buddies we changed our name + OnScreenNameChanged(oldName); + } + } + + + + internal void SetHasSpace(bool hasSpaceValue) + { + hasSpace = hasSpaceValue; + } + + internal void SetNickName(string newNick) + { + nickName = newNick; + } + + internal void SetPersonalMessage(PersonalMessage newpmessage) + { + if (personalMessage != newpmessage) + { + personalMessage = newpmessage; + // notify the user we changed our display message + OnPersonalMessageChanged(newpmessage); + } + } + + internal void SetStatus(PresenceStatus newStatus) + { + //Becareful deadlock! + + PresenceStatus currentStatus = PresenceStatus.Unknown; + + lock (syncObject) + { + currentStatus = status; + } + + if (currentStatus != newStatus) + { + PresenceStatus oldStatus = currentStatus; + + lock (syncObject) + { + + status = newStatus; + } + + // raise an event + OnStatusChanged(oldStatus); + + // raise the online/offline events + if (oldStatus == PresenceStatus.Offline) + OnContactOnline(oldStatus); + + if (newStatus == PresenceStatus.Offline) + OnContactOffline(oldStatus); + } + + } + + /// + /// This method will lead to fire event if the DisplayImage.Sha has been changed. + /// + /// + /// + /// false: No event was fired.
+ /// true: The was fired. + ///
+ internal bool FireDisplayImageContextChangedEvent(string updatedImageContext) + { + if (DisplayImage == updatedImageContext) + return false; + + OnDisplayImageContextChanged(new DisplayImageChangedEventArgs(null, DisplayImageChangedType.UpdateTransmissionRequired)); + return true; + } + + /// + /// This method will lead to fire event if the DisplayImage.Image has been changed. + /// + /// + /// + /// false: No event was fired.
+ /// true: The event was fired. + ///
+ internal bool SetDisplayImageAndFireDisplayImageChangedEvent(DisplayImage image) + { + if (image == null) return false; + + + DisplayImageChangedEventArgs displayImageChangedArg = null; + //if ((displayImage != null && displayImage.Sha != image.Sha && displayImage.IsDefaultImage && image.Image != null) || //Transmission completed. default Image -> new Image + // (displayImage != null && displayImage.Sha != image.Sha && !displayImage.IsDefaultImage && image.Image != null) || //Transmission completed. old Image -> new Image. + // (displayImage != null && object.ReferenceEquals(displayImage, image) && displayImage.Image != null) || //Transmission completed. old Image -> updated old Image. + // (displayImage == null)) + { + + displayImageChangedArg = new DisplayImageChangedEventArgs(image, DisplayImageChangedType.TransmissionCompleted, false); + } + + if (!object.ReferenceEquals(displayImage, image)) + { + displayImage = image; + } + + SaveOriginalDisplayImageAndFireDisplayImageChangedEvent(displayImageChangedArg); + + return true; + } + + internal void SaveOriginalDisplayImageAndFireDisplayImageChangedEvent(DisplayImageChangedEventArgs arg) + { + SaveDisplayImage(displayImage); + OnDisplayImageChanged(arg); + } + + internal void NotifyManager() + { + if (AddressBookId != new Guid(WebServiceConstants.MessengerIndividualAddressBookId)) + return; + + if (NSMessageHandler == null) + return; + + NSMessageHandler.Manager.SyncProperties(this); + } + + #region Protected + + protected virtual string GetLocalContactString() + { + if (MachineGuid == Guid.Empty) + return Mail.ToLowerInvariant(); + + return Mail.ToLowerInvariant() + ";" + MachineGuid.ToString("B"); + } + + protected virtual void OnScreenNameChanged(string oldName) + { + if (ScreenNameChanged != null) + { + ScreenNameChanged(this, EventArgs.Empty); + } + } + + protected virtual void OnPersonalMessageChanged(PersonalMessage newmessage) + { + if (PersonalMessageChanged != null) + { + PersonalMessageChanged(this, EventArgs.Empty); + } + } + + protected virtual void OnStatusChanged(PresenceStatus oldStatus) + { + if (StatusChanged != null) + StatusChanged(this, new StatusChangedEventArgs(oldStatus)); + } + + protected virtual void OnContactOnline(PresenceStatus oldStatus) + { + if (ContactOnline != null) + ContactOnline(this, new StatusChangedEventArgs(oldStatus)); + } + + protected virtual void OnContactOffline(PresenceStatus oldStatus) + { + if (ContactOffline != null) + { + ContactOffline(this, new StatusChangedEventArgs(oldStatus)); + } + } + + protected virtual void OnDisplayImageChanged(DisplayImageChangedEventArgs arg) + { + if (DisplayImageChanged != null) + { + DisplayImageChanged(this, arg); + } + } + + protected virtual void OnDisplayImageContextChanged(DisplayImageChangedEventArgs arg) + { + if (DisplayImageContextChanged != null) + { + DisplayImageContextChanged(this, arg); + } + } + + protected virtual void LoadDisplayImageFromDeltas() + { + if (NSMessageHandler.ContactService.Deltas == null) + return; + + if (displayImage != null && !displayImage.IsDefaultImage) //Not default, no need to restore. + return; + + string Sha = string.Empty; + byte[] rawImageData = NSMessageHandler.ContactService.Deltas.GetRawImageDataBySiblingString(SiblingString, out Sha); + if (rawImageData != null) + { + displayImage = new DisplayImage(Mail, new MemoryStream(rawImageData)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "User " + ToString() + "'s displayimage restored.\r\n " + + "Old SHA: " + Sha + "\r\n " + + "Current SHA: " + displayImage.Sha + "\r\n"); + } + } + + protected virtual void SaveDisplayImage(DisplayImage dispImage) + { + if (NSMessageHandler.ContactService.Deltas == null || dispImage == null) + return; + + if (dispImage.Image == null || string.IsNullOrEmpty(dispImage.Sha)) + return; + + if (NSMessageHandler.ContactService.Deltas.SaveImageAndRelationship(SiblingString, dispImage.Sha, dispImage.GetRawData())) + { + NSMessageHandler.ContactService.Deltas.Save(true); + } + } + + #endregion + + #endregion + + #region Internal contact operations + + protected virtual void OnContactGroupAdded(ContactGroup group) + { + if (ContactGroupAdded != null) + ContactGroupAdded(this, new ContactGroupEventArgs(group)); + } + + protected virtual void OnContactGroupRemoved(ContactGroup group) + { + if (ContactGroupRemoved != null) + ContactGroupRemoved(this, new ContactGroupEventArgs(group)); + } + + protected virtual void OnContactBlocked() + { + if (ContactBlocked != null) + ContactBlocked(this, new EventArgs()); + } + + protected virtual void OnContactUnBlocked() + { + if (ContactUnBlocked != null) + ContactUnBlocked(this, new EventArgs()); + } + + + internal void AddContactToGroup(ContactGroup group) + { + if (!contactGroups.Contains(group)) + { + contactGroups.Add(group); + + OnContactGroupAdded(group); + } + } + + internal void RemoveContactFromGroup(ContactGroup group) + { + if (contactGroups.Contains(group)) + { + contactGroups.Remove(group); + + OnContactGroupRemoved(group); + } + } + + /// + /// Add a membership list for this contact. + /// + /// + /// Since AllowList and BlockList are mutally exclusive, adding a member to AllowList will lead to the remove of BlockList, revese is as the same. + internal void AddToList(MSNLists list) + { + if ((lists & list) == MSNLists.None) + { + lists |= list; + + if ((list & MSNLists.BlockedList) == MSNLists.BlockedList) + { + OnContactBlocked(); + } + + NotifyManager(); + } + + } + + internal void AddSibling(Contact contact) + { + lock (syncObject) + Siblings[contact.Hash] = contact; + } + + internal void AddSibling(Contact[] contacts) + { + if (contacts == null) + return; + + lock (syncObject) + { + foreach (Contact sibling in contacts) + { + Siblings[sibling.Hash] = sibling; + } + } + } + + internal void RemoveFromList(MSNLists list) + { + if ((lists & list) != MSNLists.None) + { + lists ^= list; + + // set this contact to offline when it is neither on the allow list or on the forward list + if (!(OnForwardList || OnAllowedList)) + { + status = PresenceStatus.Offline; + //also clear the groups, becase msn loose them when removed from the two lists + contactGroups.Clear(); + } + + if ((list & MSNLists.BlockedList) == MSNLists.BlockedList) + { + OnContactUnBlocked(); + } + + NotifyManager(); + } + + + } + + internal void RemoveFromList() + { + if (NSMessageHandler != null) + { + OnAllowedList = false; + OnForwardList = false; + + NotifyManager(); + } + } + + internal static MSNLists GetConflictLists(MSNLists currentLists, MSNLists newLists) + { + MSNLists conflictLists = MSNLists.None; + + if ((currentLists & MSNLists.AllowedList) != MSNLists.None && (newLists & MSNLists.BlockedList) != MSNLists.None) + { + conflictLists |= MSNLists.AllowedList; + } + + if ((currentLists & MSNLists.BlockedList) != MSNLists.None && (newLists & MSNLists.AllowedList) != MSNLists.None) + { + conflictLists |= MSNLists.BlockedList; + } + + return conflictLists; + } + + internal Guid SelectRandomEPID() + { + foreach (Guid epId in EndPointData.Keys) + { + if (epId != Guid.Empty) + return epId; + } + + return Guid.Empty; + } + + internal static string MakeHash(string account, ClientType type, Guid abId) + { + if (account == null) + throw new ArgumentNullException("account"); + + return type.ToString() + ":" + account.ToLowerInvariant() + ";via=" + abId.ToString("D").ToLowerInvariant(); + } + + internal static string MakeHash(string account, ClientType type, string abId) + { + return type.ToString() + ":" + account.ToLowerInvariant() + ";via=" + abId.ToLowerInvariant(); + } + + internal bool HasLists(MSNLists msnlists) + { + return ((lists & msnlists) == msnlists); + } + + internal static MSNLists GetListForADL(MSNLists currentContactList) + { + if ((currentContactList & MSNLists.ReverseList) == MSNLists.ReverseList) + { + return currentContactList ^ MSNLists.ReverseList; + } + + return currentContactList; + } + + + #endregion + + public bool HasGroup(ContactGroup group) + { + return contactGroups.Contains(group); + } + + public void UpdateScreenName() + { + if (NSMessageHandler == null) + throw new MSNPSharpException("No valid message handler object"); + + NSMessageHandler.RequestScreenName(this); + } + + public override int GetHashCode() + { + return Hash.GetHashCode(); + } + + public static bool operator ==(Contact contact1, Contact contact2) + { + if (((object)contact1) == null && ((object)contact2) == null) + return true; + if (((object)contact1) == null || ((object)contact2) == null) + return false; + return contact1.GetHashCode() == contact2.GetHashCode(); + } + + public static bool operator !=(Contact contact1, Contact contact2) + { + return !(contact1 == contact2); + } + + public override bool Equals(object obj) + { + if (obj == null || obj.GetType() != GetType()) + return false; + + if (ReferenceEquals(this, obj)) + return true; + + return obj.GetHashCode() == GetHashCode(); + } + + public override string ToString() + { + return Hash; + } + + /// + /// Check whether two contacts represent the same user (Have the same passport account). + /// + /// + /// + public virtual bool IsSibling(Contact contact) + { + if (contact == null) + return false; + if (ClientType == contact.ClientType && Mail.ToLowerInvariant() == contact.Mail.ToLowerInvariant()) + return true; + + return false; + } + + } +}; diff --git a/MSNPSharp/ContactGroup.cs b/MSNPSharp/ContactGroup.cs new file mode 100644 index 0000000..851b396 --- /dev/null +++ b/MSNPSharp/ContactGroup.cs @@ -0,0 +1,210 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + /// + /// Used as event argument when a contactgroup is affected. + /// + [Serializable()] + public class ContactGroupEventArgs : EventArgs + { + private ContactGroup contactGroup; + + /// + /// The affected contact group + /// + public ContactGroup ContactGroup + { + get + { + return contactGroup; + } + set + { + contactGroup = value; + } + } + + /// + /// Constructor, mostly used internal by the library. + /// + /// + public ContactGroupEventArgs(ContactGroup contactGroup) + { + ContactGroup = contactGroup; + } + } + + /// + /// Defines a single contact group. + /// + [Serializable()] + public class ContactGroup + { + #region Private + + private string name; + private string guid; + private object clientData; + private bool isFavorite; + + [NonSerialized] + private NSMessageHandler nsMessageHandler = null; + + #endregion + + #region Internal + + /// + /// Constructor, used internally by the library. + /// + /// + /// + /// + /// + internal ContactGroup(string name, string guid, NSMessageHandler nsMessageHandler, bool isFavorite) + { + this.name = name; + this.guid = guid; + this.isFavorite = isFavorite; + this.nsMessageHandler = nsMessageHandler; + } + + private ContactGroup() + : this(String.Empty, System.Guid.NewGuid().ToString(), null, false) + { + } + + /// + /// Used by nameserver. + /// + /// + internal void SetName(string name) + { + this.name = name; + } + #endregion + + #region Public + + /// + /// The notification message handler which controls this contact object + /// + internal NSMessageHandler NSMessageHandler + { + get + { + return nsMessageHandler; + } + } + + /// + /// The custom data specified by the client programmer + /// + /// The application programmer can define it's own data here. It is not used by MSNPSharp. + public object ClientData + { + get + { + return clientData; + } + set + { + clientData = value; + } + } + + /// + /// Name of the contactgroup + /// + public string Name + { + get + { + return name; + } + set + { + if (NSMessageHandler != null) + { + NSMessageHandler.ContactService.RenameGroup(this, value); + } + } + } + + /// + /// The unique contactgroup ID assigned by MSN + /// + public string Guid + { + get + { + return guid; + } + } + + public bool IsFavorite + { + get + { + return isFavorite; + } + } + + /// + /// Returns the ID field as hashcode. This is necessary to compare contactgroups. + /// + /// + override public int GetHashCode() + { + return guid.GetHashCode(); + } + + /// + /// Equals two contacgroups based on their ID + /// + /// + /// + public override bool Equals(object obj) + { + ContactGroup cg = obj as ContactGroup; + return cg != null && cg.Guid == guid; + } + + #endregion + } +}; diff --git a/MSNPSharp/ContactGroupList.cs b/MSNPSharp/ContactGroupList.cs new file mode 100644 index 0000000..5ed1843 --- /dev/null +++ b/MSNPSharp/ContactGroupList.cs @@ -0,0 +1,131 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections; +using System.Globalization; +using System.Collections.Generic; + +namespace MSNPSharp +{ + [Serializable()] + public class ContactGroupList : IEnumerable + { + List list = new List(); + + [NonSerialized] + NSMessageHandler nsMessageHandler = null; + + internal void AddGroup(ContactGroup group) + { + if (this[group.Guid] == null) + list.Add(group); + else + this[group.Guid].SetName(group.Name); + } + internal void RemoveGroup(ContactGroup group) + { + list.Remove(group); + } + + internal ContactGroupList(NSMessageHandler handler) + { + nsMessageHandler = handler; + } + + public virtual void Add(string name) + { + if (nsMessageHandler == null) + throw new MSNPSharpException("No nameserver handler defined"); + + nsMessageHandler.ContactService.AddContactGroup(name); + } + + public virtual void Remove(ContactGroup group) + { + if (nsMessageHandler == null) + throw new MSNPSharpException("No nameserver handler defined"); + + if (this[group.Guid] != null) + nsMessageHandler.ContactService.RemoveContactGroup(group); + else + throw new MSNPSharpException("Contactgroup not defined in this list"); + } + + public ContactGroup GetByName(string name) + { + foreach (ContactGroup group in list) + { + if (group.Name == name) + return group; + } + + return null; + } + + public ContactGroup this[string guid] + { + get + { + foreach (ContactGroup group in list) + { + if (group.Guid.ToLower(CultureInfo.InvariantCulture) == guid.ToLower(CultureInfo.InvariantCulture)) + return group; + } + return null; + } + } + + public ContactGroup FavoriteGroup + { + get + { + foreach (ContactGroup group in list) + { + if (group.IsFavorite) + return group; + } + return null; + } + } + + public IEnumerator GetEnumerator() + { + return list.GetEnumerator(); + } + + public void Clear() + { + list.Clear(); + } + } +}; diff --git a/MSNPSharp/ContactList.cs b/MSNPSharp/ContactList.cs new file mode 100644 index 0000000..6a44daf --- /dev/null +++ b/MSNPSharp/ContactList.cs @@ -0,0 +1,545 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Threading; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + [Serializable()] + public class ContactList : Dictionary + { + private static ClientType[] clientTypes = (ClientType[])Enum.GetValues(typeof(ClientType)); + + [NonSerialized] + private NSMessageHandler nsMessageHandler; + [NonSerialized] + private object syncRoot; + + private Guid addressBookId = Guid.Empty; + private Owner owner = null; + + private ContactList() + { + } + + private void Initialize(NSMessageHandler handler, Owner owner) + { + nsMessageHandler = handler; + this.owner = owner; + } + + public ContactList(NSMessageHandler handler) + { + addressBookId = new Guid(WebServiceConstants.MessengerIndividualAddressBookId); + nsMessageHandler = handler; + } + + public ContactList(string abId, Owner owner, NSMessageHandler handler) + { + addressBookId = new Guid(abId); + Initialize(handler, owner); + } + + public ContactList(Guid abId, Owner owner, NSMessageHandler handler) + { + addressBookId = abId; + Initialize(handler, owner); + } + + #region ListEnumerators + + public class ListEnumerator : IEnumerator + { + private Enumerator baseEnum; + private MSNLists listFilter; + + public ListEnumerator(Enumerator listEnum, MSNLists filter) + { + baseEnum = listEnum; + listFilter = filter; + } + + public virtual bool MoveNext() + { + if (listFilter == MSNLists.None) + { + return baseEnum.MoveNext(); + } + else + { + while (baseEnum.MoveNext()) + { + if (Current.HasLists(listFilter)) + return true; + } + return false; + } + } + + object IEnumerator.Current + { + get + { + return baseEnum.Current; + } + } + + public Contact Current + { + get + { + return baseEnum.Current.Value; + } + } + + public void Reset() + { + } + + public void Dispose() + { + baseEnum.Dispose(); + } + + public IEnumerator GetEnumerator() + { + return this; + } + } + + public class EmailListEnumerator : ContactList.ListEnumerator + { + public EmailListEnumerator(Enumerator listEnum) + : base(listEnum, MSNLists.None) + { + } + + public override bool MoveNext() + { + while (base.MoveNext()) + { + if (Current.Guid != Guid.Empty && Current.IsMessengerUser == false) + return true; + } + return false; + } + } + + #endregion + + #region Lists + + public ContactList.ListEnumerator Forward + { + get + { + return new ContactList.ListEnumerator(GetEnumerator(), MSNLists.ForwardList); + } + } + + public ContactList.ListEnumerator Allowed + { + get + { + return new ContactList.ListEnumerator(GetEnumerator(), MSNLists.AllowedList); + } + } + + public ContactList.ListEnumerator BlockedList + { + get + { + return new ContactList.ListEnumerator(GetEnumerator(), MSNLists.BlockedList); + } + } + + public ContactList.ListEnumerator Reverse + { + get + { + return new ContactList.ListEnumerator(GetEnumerator(), MSNLists.ReverseList); + } + } + + public ContactList.ListEnumerator Pending + { + get + { + return new ContactList.ListEnumerator(GetEnumerator(), MSNLists.PendingList); + } + } + + public ContactList.ListEnumerator All + { + get + { + return new ContactList.ListEnumerator(GetEnumerator(), MSNLists.None); + } + } + + public ContactList.ListEnumerator Email + { + get + { + return new ContactList.EmailListEnumerator(GetEnumerator()); + } + } + + #endregion + + public object SyncRoot + { + get + { + if (syncRoot == null) + { + object newobj = new object(); + Interlocked.CompareExchange(ref syncRoot, newobj, null); + } + return syncRoot; + } + } + + /// + /// The addressbook identifier of this addressbook. + /// + public Guid AddressBookId + { + get + { + return addressBookId; + } + } + + /// + /// The owner of the contactlist. This is the identity that logged into the messenger network. + /// + public Owner Owner + { + get + { + return owner; + } + } + + /// + /// Get the specified contact. + /// If the contact does not exist, return null + /// + /// + /// + /// If the contact does not exist, return null. + /// If the specified account has multi-clienttype, the contact with type + /// will be returned first. + /// If there's no PassportMember with the specified account, the contact with type + /// will be returned. Then the next is + /// , and so on... + /// + public Contact GetContact(string account) + { + if (HasContact(account, ClientType.PassportMember)) + return GetContact(account, ClientType.PassportMember); + + if (HasContact(account, ClientType.EmailMember)) + return GetContact(account, ClientType.EmailMember); + + if (HasContact(account, ClientType.PhoneMember)) + return GetContact(account, ClientType.PhoneMember); + + if (HasContact(account, ClientType.LCS)) + return GetContact(account, ClientType.LCS); + + return null; + } + + /// + /// Get the specified contact. + /// This overload will set the contact name to a specified value (if the contact exists.). + /// If the contact does not exist, return null + /// + /// + /// + /// + /// If the contact does not exist, return null. + /// If the specified account has multi-clienttype, the contact with type + /// will be returned first. + /// If there's no PassportMember with the specified account, the contact with type + /// will be returned.Then the next is + /// , and so on... + /// + internal Contact GetContact(string account, string name) + { + Contact contact = GetContact(account); + if (contact != null) + lock (SyncRoot) + contact.SetName(name); + + return contact; + } + + /// + /// Get a contact with specified account and client type, if the contact does not exist, create it. + /// This overload will set the contact name to a specified value. + /// + /// + /// The new name you want to set. + /// + /// + /// A object. + /// If the contact does not exist, create it. + /// + internal Contact GetContact(string account, string name, ClientType type) + { + Contact contact = GetContact(account, type); + + lock (SyncRoot) + contact.SetName(name); + + return contact; + } + + /// + /// Get a contact with specified account and client type, if the contact does not exist, create it. + /// + /// Account (Mail) of a contact + /// Contact type. + /// + /// A object. + /// If the contact does not exist, create it. + /// + internal Contact GetContact(string account, ClientType type) + { + int hash = Contact.MakeHash(account, type, AddressBookId.ToString("D")).GetHashCode(); + + lock (SyncRoot) + { + if (ContainsKey(hash)) + { + return this[hash]; + } + + Contact tmpContact = new Contact(AddressBookId, account, type, 0, nsMessageHandler); + + + Add(hash, tmpContact); + } + + return GetContact(account, type); + } + + public Contact GetContactByGuid(Guid guid) + { + if (guid != Guid.Empty) + { + lock (SyncRoot) + { + foreach (Contact contact in Values) + { + if (contact.Guid == guid) + return contact; + } + } + } + return null; + } + + public Contact GetContactByCID(long cid) + { + if (cid != 0) + { + lock (SyncRoot) + { + foreach (Contact contact in Values) + { + if (contact.CID == cid) + return contact; + } + } + } + return null; + } + + public Contact this[string account] + { + get + { + return GetContact(account); + } + set + { + this[account, value.ClientType] = value; + } + } + + public Contact this[string account, ClientType type] + { + get + { + return GetContact(account, type); + } + set + { + this[account, type] = value; + } + } + + /// + /// Check whether the specified account is in the contact list. + /// + /// + /// + public bool HasContact(string account) + { + foreach (ClientType ct in clientTypes) + { + if (HasContact(account, ct)) + return true; + } + return false; + } + + /// + /// Check whether the account with specified client type is in the contact list. + /// + /// + /// + /// + public bool HasContact(string account, ClientType type) + { + return ContainsKey(Contact.MakeHash(account, type, AddressBookId.ToString("D")).GetHashCode()); + } + + public void CopyTo(Contact[] array, int index) + { + lock (SyncRoot) + Values.CopyTo(array, index); + } + + /// + /// Copy the whole contact list out. + /// + /// + public Contact[] ToArray() + { + lock (SyncRoot) + { + Contact[] array = new Contact[Values.Count]; + CopyTo(array, 0); + return array; + } + } + + /// + /// Remove all the contacts with the specified account. + /// + /// + internal void Remove(string account) + { + foreach (ClientType ct in clientTypes) + { + if (HasContact(account, ct)) + Remove(account, ct); + } + } + + /// + /// Remove a contact with specified account and client type. + /// + /// + /// + internal void Remove(string account, ClientType type) + { + lock (SyncRoot) + { + Remove(Contact.MakeHash(account, type, AddressBookId.ToString("D")).GetHashCode()); + } + } + + /// + /// Set the owner for default addressbook. This funcation can be only called once. + /// + /// + internal void SetOwner(Owner owner) + { + if (AddressBookId != new Guid(WebServiceConstants.MessengerIndividualAddressBookId)) + { + throw new InvalidOperationException("Only default addressbook can call this function."); + } + + if (Owner != null) + { + throw new InvalidOperationException("Owner already set."); + } + + if (owner.AddressBookId != new Guid(WebServiceConstants.MessengerIndividualAddressBookId)) + { + throw new InvalidOperationException("Invalid owner: This is not the owner for default addressbook."); + } + + this.owner = owner; + } + + public bool HasMultiType(string account) + { + int typecount = 0; + foreach (ClientType ct in clientTypes) + { + if (HasContact(account, ct) && ++typecount > 1) + return true; + } + return false; + } + + /// + /// Reset the contact list and clear the owner. + /// + public void Reset() + { + if (Owner != null) + { + Owner.Emoticons.Clear(); + Owner.EndPointData.Clear(); + Owner.LocalEndPointClientCapacities = ClientCapacities.None; + Owner.LocalEndPointClientCapacitiesEx = ClientCapacitiesEx.None; + } + + Clear(); + owner = null; + } + } +}; \ No newline at end of file diff --git a/MSNPSharp/ContactManager.cs b/MSNPSharp/ContactManager.cs new file mode 100644 index 0000000..80d2337 --- /dev/null +++ b/MSNPSharp/ContactManager.cs @@ -0,0 +1,244 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace MSNPSharp +{ + internal sealed class ContactManager + { + #region Fields + private NSMessageHandler nsMessageHandler = null; + + private Dictionary defaultContactPage = new Dictionary(); + private Dictionary otherContactPage = new Dictionary(); + + #endregion + + #region Properties + + internal NSMessageHandler NSMessageHandler + { + get { return nsMessageHandler; } + } + + #endregion + + #region Constructors + + public ContactManager(NSMessageHandler handler) + { + nsMessageHandler = handler; + } + + #endregion + + #region Private functions + + private string AddToDefaultContactPage(Contact contact) + { + string key = GetContactKey(contact); + if (contact.AddressBookId == new Guid(WebServiceConstants.MessengerIndividualAddressBookId)) + { + + lock (defaultContactPage) + defaultContactPage[key] = contact; + } + + return key; + } + + private void DisplayImageChanged(object sender, EventArgs e) + { + Contact contact = sender as Contact; + if (contact == null) + return; + + SyncDisplayImage(contact); + } + + private string AddToOtherContactPage(Contact contact) + { + string key = GetContactKey(contact); + if (contact.AddressBookId != new Guid(WebServiceConstants.MessengerIndividualAddressBookId)) + { + + lock (otherContactPage) + { + if (!otherContactPage.ContainsKey(key)) + { + otherContactPage[key] = contact; + } + else + { + otherContactPage[key].AddSibling(contact); + } + } + + if (NeedSync(key)) + { + lock (defaultContactPage) + { + if (contact != defaultContactPage[key]) + defaultContactPage[key].AddSibling(contact); + } + } + } + + return key; + } + + private bool NeedSync(Contact contact) + { + return NeedSync(GetContactKey(contact)); + } + + private bool NeedSync(string key) + { + lock (defaultContactPage) + return defaultContactPage.ContainsKey(key); + } + + private bool Sync(string key) + { + lock (defaultContactPage) + { + if (!NeedSync(key)) + return false; + + Contact root = defaultContactPage[key]; + + if (root.Siblings.Count > 0) + { + SyncProperties(root); + } + + } + + return true; + } + + #endregion + + #region Public functions + + public void SyncProperties(Contact root) + { + lock (root.SyncObject) + { + foreach (Contact sibling in root.Siblings.Values) + { + if (sibling == root) + continue; + + sibling.SetList(root.Lists); + sibling.SetIsMessengerUser(root.IsMessengerUser); + + } + } + } + + public void SyncDisplayImage(Contact initator) + { + if (initator.AddressBookId == new Guid(WebServiceConstants.MessengerIndividualAddressBookId)) + { + + if (initator.Siblings.Count > 0) + { + lock (initator.SyncObject) + { + foreach (Contact sibling in initator.Siblings.Values) + { + if (sibling != initator) + sibling.DisplayImage = initator.DisplayImage; + } + } + } + } + else + { + string key = GetContactKey(initator); + + Contact root = null; + lock (otherContactPage) + { + if (!otherContactPage.ContainsKey(key)) + return; + + root = otherContactPage[key]; + } + + if (root.Siblings.Count > 0) + { + lock (root.SyncObject) + { + foreach (Contact sibling in root.Siblings.Values) + { + if (sibling != root) + sibling.DisplayImage = root.DisplayImage; + } + } + } + } + } + + public void Add(Contact contact) + { + string key = AddToDefaultContactPage(contact); + AddToOtherContactPage(contact); + contact.DisplayImageChanged += new EventHandler(DisplayImageChanged); + if (!NeedSync(key)) + { + return; + } + + Sync(key); + + } + + public string GetContactKey(Contact contact) + { + return contact.ClientType.ToString().ToLowerInvariant() + ":" + contact.Mail.ToLowerInvariant(); + } + + public void Reset() + { + lock (defaultContactPage) + defaultContactPage.Clear(); + lock (otherContactPage) + otherContactPage.Clear(); + } + #endregion + } +} diff --git a/MSNPSharp/Conversation.cs b/MSNPSharp/Conversation.cs new file mode 100644 index 0000000..a3e359e --- /dev/null +++ b/MSNPSharp/Conversation.cs @@ -0,0 +1,1179 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Threading; +using System.Collections; +using System.Diagnostics; +using System.Collections.Generic; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + using MSNPSharp.DataTransfer; + + internal abstract class MessageObject + { + protected object innerObject = null; + + public object InnerObject + { + get { return innerObject; } + } + } + + internal class UserTypingObject : MessageObject + { + + } + + internal class NudgeObject : MessageObject { } + internal class TextMessageObject : MessageObject + { + public TextMessageObject(TextMessage message) + { + innerObject = message; + } + } + + internal class EmoticonObject : MessageObject + { + private EmoticonType type; + + public EmoticonType Type + { + get { return type; } + } + public EmoticonObject(List iconlist, EmoticonType icontype) + { + innerObject = iconlist; + type = icontype; + } + } + + /// + /// A facade to the underlying switchboard and YIM session. + /// + /// + /// Conversation implements a few features for the ease of the application programmer. It provides + /// directly basic common functionality. However, if you need to perform more advanced actions, or catch + /// other events you have to directly use the underlying switchboard handler, or switchboard processor. + /// Conversation automatically requests emoticons used by remote contacts. + /// + public class Conversation + { + #region Private + + #region Members + + private Messenger _messenger = null; + private SBMessageHandler _switchboard = null; + private bool ended = false; + private bool ending = false; + private ConversationState conversationState = ConversationState.None; + + private bool autoRequestEmoticons = true; + private bool autoKeepAlive = false; + + private List _pendingInviteContacts = new List(0); + private List _contacts = new List(0); + private Contact _firstContact = null; + private object _syncObject = new object(); + + private Queue _messageQueues = new Queue(0); + private ConversationType _type = ConversationType.None; + private int keepalivePeriod = 30000; + + private Timer keepaliveTimer = null; + #endregion + + private void transferSession_TransferAborted(object sender, EventArgs e) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Emoticon aborted", GetType().Name); + + P2PTransferSession session = sender as P2PTransferSession; + OnMSNObjectDataTransferCompleted(sender, + new MSNObjectDataTransferCompletedEventArgs(session.ClientData as MSNObject, true, session.TransferProperties.RemoteContact, session.TransferProperties.RemoteContactEndPointID)); + } + + private void transferSession_TransferFinished(object sender, EventArgs e) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Emoticon received", GetType().Name); + + P2PTransferSession session = sender as P2PTransferSession; + OnMSNObjectDataTransferCompleted(sender, + new MSNObjectDataTransferCompletedEventArgs(session.ClientData as MSNObject, false, session.TransferProperties.RemoteContact, session.TransferProperties.RemoteContactEndPointID)); + + } + + private bool AddContact(Contact contact) + { + lock (_contacts) + { + if (_contacts.Contains(contact)) + return false; ; + _contacts.Add(contact); + } + + return true; + } + + private bool RemoveContact(Contact contact) + { + lock (_contacts) + { + return _contacts.Remove(contact); + } + } + + private void ClearContacts() + { + lock (_contacts) + _contacts.Clear(); + } + + private static void KeepAlive(object state) + { + Conversation convers = state as Conversation; + if (convers.AutoKeepAlive) + { + if ((convers.Type & ConversationType.SwitchBoard) == ConversationType.SwitchBoard) + { + if (convers.conversationState >= ConversationState.SwitchboardRequestSent && + convers.conversationState < ConversationState.SwitchboardEnded) + { + convers._switchboard.SendKeepAliveMessage(); + } + } + } + } + + private void IniCommonSettings() + { + if (_switchboard == null) + { + _switchboard = new SBMessageHandler(Messenger.Nameserver); + + } + + //Must call after _switchboard and _yimHandler have been initialized. + AttachEvents(_switchboard); + + conversationState = ConversationState.ConversationCreated; + } + + private bool IsPendingContact(Contact contact) + { + lock (_pendingInviteContacts) + { + foreach (Contact pendingContact in _pendingInviteContacts) + { + if (pendingContact.IsSibling(contact)) + return true; + } + + return false; + } + } + + private void PendingContactEnqueue(Contact pendingContact) + { + lock (_pendingInviteContacts) + { + if (!_pendingInviteContacts.Contains(pendingContact)) + _pendingInviteContacts.Add(pendingContact); + } + } + + private void MessageEnqueue(MessageObject message) + { + lock (_messageQueues) + { + _messageQueues.Enqueue(message); + } + } + + private void SwitchBoardInvitePendingContacts() + { + List pendingInviteContacts = new List(_pendingInviteContacts); + foreach (Contact contact in pendingInviteContacts) + { + if (contact.Status == PresenceStatus.Offline) + { + lock (_pendingInviteContacts) + { + _pendingInviteContacts.Remove(contact); + } + } + } + + pendingInviteContacts = new List(_pendingInviteContacts); + foreach (Contact contact in pendingInviteContacts) + { + if (contact.Status != PresenceStatus.Offline) + { + _switchboard.Invite(contact); + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "SwitchBoard " + _switchboard.SessionHash + " inviting user: " + contact.Mail); + } + } + } + + private void AttachEvents(SBMessageHandler switchboard) + { + DetachEvents(switchboard); + + switchboard.AllContactsLeft += new EventHandler(OnAllContactsLeft); + switchboard.ContactJoined += new EventHandler(OnContactJoined); + switchboard.ContactLeft += new EventHandler(OnContactLeft); + switchboard.EmoticonDefinitionReceived += new EventHandler(OnEmoticonDefinitionReceived); + switchboard.ExceptionOccurred += new EventHandler(OnExceptionOccurred); + switchboard.NudgeReceived += new EventHandler(OnNudgeReceived); + switchboard.ServerErrorReceived += new EventHandler(OnServerErrorReceived); + switchboard.SessionClosed += new EventHandler(OnSessionClosed); + switchboard.SessionEstablished += new EventHandler(OnSessionEstablished); + switchboard.TextMessageReceived += new EventHandler(OnTextMessageReceived); + switchboard.UserTyping += new EventHandler(OnUserTyping); + switchboard.WinkReceived += new EventHandler(OnWinkReceived); + } + + private void DetachEvents(SBMessageHandler switchboard) + { + switchboard.AllContactsLeft -= (OnAllContactsLeft); + switchboard.ContactJoined -= (OnContactJoined); + switchboard.ContactLeft -= (OnContactLeft); + switchboard.EmoticonDefinitionReceived -= (OnEmoticonDefinitionReceived); + switchboard.ExceptionOccurred -= (OnExceptionOccurred); + switchboard.NudgeReceived -= (OnNudgeReceived); + switchboard.ServerErrorReceived -= (OnServerErrorReceived); + switchboard.SessionClosed -= (OnSessionClosed); + switchboard.SessionEstablished -= (OnSessionEstablished); + switchboard.TextMessageReceived -= (OnTextMessageReceived); + switchboard.UserTyping -= (OnUserTyping); + switchboard.WinkReceived -= (OnWinkReceived); + } + + + private void SwitchBoardEnd(object param) + { + try + { + if ((bool)param == false) + { + Switchboard.Close(); + } + + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[SwitchBoardEnd] An error occured while ending the switchboard: " + Switchboard.SessionHash + + "\r\n Error Message: " + ex.Message); + } + + conversationState = ConversationState.SwitchboardEnded; + } + + private Contact GetFirstJoinedContact() + { + lock (Contacts) + { + foreach (Contact contact in Contacts) + { + if (!contact.IsSibling(Messenger.ContactList.Owner)) + { + return contact; + } + } + } + + return null; + } + + private bool SetFirstJoinedContact(Contact firstJoinedContact) + { + lock (_syncObject) + { + if (RemoteOwner == null) + { + _firstContact = firstJoinedContact; + return true; + } + } + + return false; + } + + private bool SetNextRemoteOwner() + { + lock (_syncObject) + { + Contact oldOwner = RemoteOwner; + + foreach (Contact contact in Contacts) + { + if (!contact.IsSibling(Messenger.Nameserver.ContactList.Owner)) + { + if (!contact.IsSibling(oldOwner)) + { + _firstContact = contact; + return true; + } + } + } + + return false; + } + } + + #endregion + + + #region Protected + + protected void OnMSNObjectDataTransferCompleted(object sender, MSNObjectDataTransferCompletedEventArgs e) + { + if (MSNObjectDataTransferCompleted != null) + MSNObjectDataTransferCompleted(this, new ConversationMSNObjectDataTransferCompletedEventArgs(sender as P2PTransferSession, e)); + } + + + protected virtual void OnConversationEnded(Conversation conversation) + { + if (Ended) return; + Ended = true; + + conversationState = ConversationState.ConversationEnded; + if (ending) + { + DetachEvents(_switchboard); + ending = false; + } + + _messenger.Conversations.Remove(this); + + + ClearContacts(); + + lock (_pendingInviteContacts) + _pendingInviteContacts.Clear(); + + if (ConversationEnded != null) + { + ConversationEnded(this, new ConversationEndEventArgs(conversation)); + } + } + + #region Event operation + + + protected virtual void OnWinkReceived(object sender, WinkEventArgs e) + { + _type |= ConversationType.Chat; + if (WinkReceived != null) + WinkReceived(this, e); + } + + protected virtual void OnUserTyping(object sender, ContactEventArgs e) + { + _type |= ConversationType.Chat; + if (UserTyping != null) + UserTyping(this, e); + } + + protected virtual void OnTextMessageReceived(object sender, TextMessageEventArgs e) + { + _type |= ConversationType.Chat; + + if (TextMessageReceived != null) + TextMessageReceived(this, e); + } + + protected virtual void OnSessionEstablished(object sender, EventArgs e) + { + if ((_type & ConversationType.SwitchBoard) == ConversationType.SwitchBoard) + { + SwitchBoardInvitePendingContacts(); + } + + if (SessionEstablished != null) + SessionEstablished(this, e); + } + + protected virtual void OnSessionClosed(object sender, EventArgs e) + { + if (sender.GetType() == typeof(SBMessageHandler)) + { + conversationState = ConversationState.SwitchboardEnded; + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, sender.GetType().ToString() + " session :" + _switchboard.SessionHash + " closed."); + + if (SessionClosed != null) + SessionClosed(this, e); + + Messenger.P2PHandler.RemoveSwitchboardSession(_switchboard); + + OnConversationEnded(this); + } + + protected virtual void OnServerErrorReceived(object sender, MSNErrorEventArgs e) + { + if (ServerErrorReceived != null) + ServerErrorReceived(this, e); + } + + protected virtual void OnNudgeReceived(object sender, ContactEventArgs e) + { + _type |= ConversationType.Chat; + if (NudgeReceived != null) + NudgeReceived(this, e); + } + + protected virtual void OnExceptionOccurred(object sender, ExceptionEventArgs e) + { + if (ExceptionOccurred != null) + ExceptionOccurred(this, e); + } + + protected virtual void OnEmoticonDefinitionReceived(object sender, EmoticonDefinitionEventArgs e) + { + _type |= ConversationType.Chat; + if (AutoRequestEmoticons == false) + return; + + MSNObject existing = MSNObjectCatalog.GetInstance().Get(e.Emoticon.CalculateChecksum()); + if (existing == null) + { + e.Sender.Emoticons[e.Emoticon.Sha] = e.Emoticon; + + // create a session and send the invitation + P2PMessageSession session = Messenger.P2PHandler.GetSession(Messenger.ContactList.Owner, Messenger.ContactList.Owner.MachineGuid, e.Sender, e.Sender.SelectRandomEPID()); + + MSNSLPHandler msnslpHandler = session.MasterSession; + if (msnslpHandler != null) + { + P2PTransferSession transferSession = msnslpHandler.SendInvitation(session.LocalContact, session.RemoteContact, e.Emoticon); + transferSession.DataStream = e.Emoticon.OpenStream(); + transferSession.ClientData = e.Emoticon; + + transferSession.TransferAborted += new EventHandler(transferSession_TransferAborted); + transferSession.TransferFinished += new EventHandler(transferSession_TransferFinished); + + MSNObjectCatalog.GetInstance().Add(e.Emoticon); + } + else + throw new MSNPSharpException("No MSNSLPHandler was attached to the p2p message session. An emoticon invitation message could not be send."); + } + else + { + //If exists, fire the event. + OnMSNObjectDataTransferCompleted(sender, new MSNObjectDataTransferCompletedEventArgs(existing, false, e.Sender, Guid.Empty)); + } + + + if (EmoticonDefinitionReceived != null) + EmoticonDefinitionReceived(this, e); + } + + protected virtual void OnContactLeft(object sender, ContactConversationEventArgs e) + { + if (e.EndPoint != Guid.Empty) + return; + + RemoveContact(e.Contact); + + if (ContactLeft != null) + ContactLeft(this, e); + + if (e.Contact.IsSibling(RemoteOwner)) + { + Contact oldOwner = RemoteOwner; + if (SetNextRemoteOwner()) + { + OnRemoteOwnerChanged(new ConversationRemoteOwnerChangedEventArgs(oldOwner, RemoteOwner)); + } + } + } + + protected virtual void OnContactJoined(object sender, ContactConversationEventArgs e) + { + if (e.EndPoint != Guid.Empty) + { + //Wait until contacts from all locations have joined. + return; + } + + if (!AddContact(e.Contact)) + return; + + if (!_messenger.Conversations.Contains(this)) + { + _messenger.Conversations.Add(this); + } + + lock (_pendingInviteContacts) + _pendingInviteContacts.Remove(e.Contact); + + conversationState = ConversationState.OneRemoteUserJoined; + + if (!e.Contact.IsSibling(Messenger.ContactList.Owner)) + { + SetFirstJoinedContact(e.Contact); + } + + lock (_messageQueues) + { + while (_messageQueues.Count > 0) + { + MessageObject msgobj = _messageQueues.Dequeue(); + if (msgobj is TextMessageObject) + { + SendTextMessage(msgobj.InnerObject as TextMessage); + } + + if (msgobj is NudgeObject) + { + SendNudge(); + } + + if (msgobj is EmoticonObject) + { + SendEmoticonDefinitions(msgobj.InnerObject as List, (msgobj as EmoticonObject).Type); + } + } + } + + + if (ContactJoined != null) + ContactJoined(this, e); + } + + protected virtual void OnAllContactsLeft(object sender, EventArgs e) + { + if (AllContactsLeft != null) + AllContactsLeft(this, e); + EndSwitchBoardSession(true); + } + + /// + /// Create a new conversation which contains the same users as the expired one. + /// + /// A new conversation. + /// The current conversation is not expired. + protected virtual Conversation ReCreate() + { + if (conversationState == ConversationState.OneRemoteUserJoined || + conversationState == ConversationState.SwitchboardRequestSent) + { + return this; + } + + if (RemoteOwner.Status == PresenceStatus.Offline) + { + throw new InvalidOperationException("Contact " + RemoteOwner.Mail + " not online, please send offline message instead."); + } + + if ((_type & ConversationType.SwitchBoard) == ConversationType.SwitchBoard) + { + Messenger.Nameserver.RequestSwitchboard(_switchboard, this); + + conversationState = ConversationState.SwitchboardRequestSent; + } + + + Ended = false; + + + //This is a very important priciple: + //If all contacts left, we try to re-invite the first contact ONLY. + PendingContactEnqueue(RemoteOwner); + + return this; + } + + protected virtual void OnRemoteOwnerChanged(ConversationRemoteOwnerChangedEventArgs e) + { + if (RemoteOwnerChanged != null) + RemoteOwnerChanged(this, e); + } + + + #endregion + + #endregion + + #region Internal + + #endregion + + #region Public Events + + /// + /// Fired when the owner is the only contact left. If the owner leaves too the connection is automatically closed by the server. + /// + public event EventHandler AllContactsLeft; + + /// + /// Fired when the session is closed, either by the server or by the local client. + /// + public event EventHandler SessionClosed; + + /// + /// Occurs when a switchboard connection has been made and the initial handshaking commands are send. This indicates that the session is ready to invite or accept other contacts. + /// + public event EventHandler SessionEstablished; + + /// + /// Fired when a contact joins. In case of a conversation with two people in it this event is called with the remote contact specified in the event argument. + /// + public event EventHandler ContactJoined; + /// + /// Fired when a contact leaves the conversation. + /// + public event EventHandler ContactLeft; + + /// + /// Fired when a message is received from any of the other contacts in the conversation. + /// + public event EventHandler TextMessageReceived; + + /// + /// Fired when a contact sends a emoticon definition. + /// + public event EventHandler EmoticonDefinitionReceived; + + public event EventHandler WinkReceived; + + /// + /// Fired when a contact sends a nudge + /// + public event EventHandler NudgeReceived; + + /// + /// Fired when any of the other contacts is typing a message. + /// + public event EventHandler UserTyping; + + /// + /// Occurs when an exception is thrown while handling the incoming or outgoing messages. + /// + public event EventHandler ExceptionOccurred; + + /// + /// Occurs when the MSN Switchboard Server sends us an error. + /// + public event EventHandler ServerErrorReceived; + + /// + /// Occurs after the remote owner left a multiple user conversation. + /// + public event EventHandler RemoteOwnerChanged; + + #endregion + + #region Public + /// + /// Fired when the data transfer for a MSNObject finished or aborted. + /// + public event EventHandler MSNObjectDataTransferCompleted; + + /// + /// Occurs when a new conversation is ended (all contacts in the conversation have left or is called). + /// + public event EventHandler ConversationEnded; + + #region Properties + + /// + /// Contacts once or currently in the conversation. + /// + public List Contacts + { + get + { + return _contacts; + } + } + + /// + /// Indicates the type of current available switchboard in this conversation. + /// + public ConversationType Type + { + get { return _type; } + } + + /// + /// Indicates whether the conversation is ended by user.
+ /// If a conversation is ended, it can't be used to send any message. + ///
+ public bool Ended + { + get + { + lock (_syncObject) + return ended; + } + + internal set + { + lock (_syncObject) + ended = value; + } + } + + /// + /// Indicates whether emoticons from remote contacts are automatically retrieved + /// + public bool AutoRequestEmoticons + { + get + { + return autoRequestEmoticons; + } + set + { + autoRequestEmoticons = value; + } + } + + /// + /// Indicates whether the conversation will never expired until the owner close it.
+ /// If true, will never fired and a keep-alive message will send to the switchboard every seconds. + ///
+ /// Setting this property on an ended conversation. + /// Setting this property for a YIM conversation or an expired conversation. + public bool AutoKeepAlive + { + get + { + if ((_type & ConversationType.YIM) == ConversationType.YIM) + return true; + + return autoKeepAlive; + } + + set + { + if (Ended) + { + throw new InvalidOperationException("Conversation ended."); + } + + if ((_type & ConversationType.YIM) == ConversationType.YIM) + { + //YIM handlers, expired handlers. Should I throw an exception here? + throw new NotSupportedException("Cannot set keep-alive property to true for this conversation type."); + } + + + if (value && autoKeepAlive != value) + { + if ((_type & ConversationType.SwitchBoard) == ConversationType.SwitchBoard || _type == ConversationType.None) + { + autoKeepAlive = value; + keepaliveTimer = new Timer(new TimerCallback(KeepAlive), this, keepalivePeriod, keepalivePeriod); + return; + } + + } + + if (!value && autoKeepAlive != value) + { + autoKeepAlive = value; + keepaliveTimer.Dispose(); + keepaliveTimer = null; + } + } + } + + /// + /// The period between two keep-alive messages sent (In second). + /// + public int KeepAliveMessagePeriod + { + get { return keepalivePeriod / 1000; } + set + { + keepalivePeriod = value * 1000; + if (keepaliveTimer != null) + keepaliveTimer.Change(keepalivePeriod, keepalivePeriod); + else + keepaliveTimer = new Timer(new TimerCallback(KeepAlive), this, keepalivePeriod, keepalivePeriod); + } + } + + /// + /// Messenger that created the conversation + /// + public Messenger Messenger + { + get + { + return _messenger; + } + set + { + _messenger = value; + } + } + + /// + /// The switchboard handler. Handles incoming/outgoing messages.
+ /// If the conversation ended, this property will be null. + ///
+ public SBMessageHandler Switchboard + { + get + { + if ((_type & ConversationType.SwitchBoard) != ConversationType.SwitchBoard) + { + return null; + } + else + { + return _switchboard; + } + } + } + + /// + /// The remote owner of this conversation. + /// + public Contact RemoteOwner + { + get { return _firstContact; } + } + + #endregion + + /// + /// Constructor. + /// + /// The messenger object that requests the conversation. + /// The switchboard to interface to. + internal Conversation(Messenger parent, SBMessageHandler sbHandler) + { + _switchboard = sbHandler; + _type = ConversationType.SwitchBoard; + _messenger = parent; + IniCommonSettings(); + conversationState = ConversationState.SwitchboardRequestSent; + } + + /// + /// Constructor. + /// + /// The messenger object that requests the conversation. + internal Conversation(Messenger parent) + { + _messenger = parent; + + _type = ConversationType.None; + IniCommonSettings(); + } + + /// + /// Invite a remote contact to join the conversation. + /// + /// Contact account + /// Contact type + /// Operating on an ended conversation. + /// Inviting mutiple YIM users into a YIM conversation, invite YIM users to a switchboard conversation, or passport members are invited into YIM conversation. + public SBMessageHandler Invite(string contactMail, ClientType type) + { + if ((_type & ConversationType.YIM) == ConversationType.YIM && + type != ClientType.EmailMember) + { + throw new NotSupportedException("Only Yahoo messenger users can be invited in a YIM conversation."); + } + + + if ((_type & ConversationType.YIM) == ConversationType.YIM && + type == ClientType.EmailMember) + { + if (_contacts.Count > 1) + throw new NotSupportedException("Mutiple user not supported in YIM conversation."); + } + + if ((_type & ConversationType.SwitchBoard) == ConversationType.SwitchBoard && + (type != ClientType.PassportMember && + type != ClientType.LCS)) + { + throw new NotSupportedException("Only Passport members can be invited in a switchboard conversation."); + } + + if (_type == ConversationType.None) + { + switch (type) + { + case ClientType.EmailMember: + _type = ConversationType.YIM; + break; + + case ClientType.LCS: + case ClientType.PassportMember: + _type = ConversationType.SwitchBoard; + break; + } + } + + if (!Messenger.ContactList.HasContact(contactMail, type)) + { + throw new MSNPSharpException("Contact not on your contact list."); + } + + Contact contact = Messenger.ContactList.GetContact(contactMail, type); //Only contacts on default addressbook can join conversations. + if (contact.Status == PresenceStatus.Offline) + { + throw new InvalidOperationException("Contact " + contactMail + " not online, please send offline message instead."); + } + + if (Ended) + { + ReCreate(); + PendingContactEnqueue(contact); //Must added after recreate. + } + else + { + if (RemoteOwner == null) + { + _firstContact = contact; + } + + #region Initialize SBMessageHandler and invite. + + if ((_type & ConversationType.SwitchBoard) == ConversationType.SwitchBoard) + { + + if (conversationState == ConversationState.ConversationCreated || + conversationState == ConversationState.SwitchboardEnded || + conversationState == ConversationState.ConversationEnded) + { + PendingContactEnqueue(contact); //Enqueue the contact if user send message before it join. + Messenger.Nameserver.RequestSwitchboard(_switchboard, this); + + conversationState = ConversationState.SwitchboardRequestSent; + return _switchboard; + } + + bool inviteResult = _switchboard.Invite(contact); + if (inviteResult && _switchboard.GetRosterUniqueUserCount() > 1) + { + _type |= ConversationType.MutipleUsers; + } + + + } + #endregion + + } + + return _switchboard; + } + + /// + /// Invite a remote contact to join the conversation. + /// + /// The remote contact to invite. + /// Operating on an expired conversation will get this exception. + /// Inviting mutiple YIM users into a YIM conversation, invite YIM users to a switchboard conversation, or passport members are invited into YIM conversation. + public SBMessageHandler Invite(Contact contact) + { + return Invite(contact.Mail, contact.ClientType); + } + + /// + /// End this conversation. + /// + public void End() + { + ending = true; + EndSwitchBoardSession(false); + } + + /// + /// + /// + /// + /// If all the contacts left the conversation, this should be true. + /// if the current user want to left, this should set to false. + private void EndSwitchBoardSession(bool remoteDisconnect) + { + if (conversationState >= ConversationState.SwitchboardRequestSent && + conversationState < ConversationState.SwitchboardEnded) + { + Thread endthread = new Thread(new ParameterizedThreadStart(SwitchBoardEnd)); //Avoid blocking the UI thread. + endthread.Start(remoteDisconnect); + } + + if (keepaliveTimer != null) + keepaliveTimer.Dispose(); + } + + /// + /// Whether the specified contact or its sibling is in the conversation. + /// + /// + /// + public bool HasContact(Contact contact) + { + if (_type == ConversationType.None) + return false; + + + if ((_type & ConversationType.SwitchBoard) == ConversationType.SwitchBoard) + { + if (_switchboard.HasContact(contact)) + return true; + + if (IsPendingContact(contact)) + return true; + } + + return false; + } + + /// + /// Sends a plain text message to all other contacts in the conversation. + /// + /// + /// This method wraps the TextMessage object in a SBMessage object and sends it over the network. + /// + /// The message to send. + /// Sending messages from an ended conversation. + public void SendTextMessage(TextMessage message) + { + _type |= ConversationType.Chat; + + if (Ended) + { + ReCreate(); + } + + if (conversationState != ConversationState.OneRemoteUserJoined) + { + MessageEnqueue(new TextMessageObject(message)); + return; + } + + + if ((_type & ConversationType.SwitchBoard) == ConversationType.SwitchBoard) + { + _switchboard.SendTextMessage(message); + } + } + + /// + /// Sends a 'user is typing..' message to the switchboard, and is received by all participants. + /// + /// Sending messages from an ended conversation. + public void SendTypingMessage() + { + _type |= ConversationType.Chat; + + if (Ended) + { + return; + } + + + if ((_type & ConversationType.SwitchBoard) == ConversationType.SwitchBoard && conversationState == ConversationState.OneRemoteUserJoined) + { + _switchboard.SendTypingMessage(); + } + } + + /// + /// Sends a 'nudge' message to the switchboard, and is received by all participants. + /// + /// Sending messages from an ended conversation. + public void SendNudge() + { + _type |= ConversationType.Chat; + + if (Ended) + { + ReCreate(); + } + + if (conversationState != ConversationState.OneRemoteUserJoined) + { + MessageEnqueue(new NudgeObject()); + return; + } + + + if ((_type & ConversationType.SwitchBoard) == ConversationType.SwitchBoard) + { + _switchboard.SendNudge(); + } + } + + /// + /// Sends the definition for a list of emoticons to all other contacts in the conversation. The client-programmer must use this function if a text messages uses multiple emoticons in a single message. + /// + /// Use this function before sending text messages which include the emoticon text. You can only send one emoticon message before the textmessage. So make sure that all emoticons used in the textmessage are included. + /// A list of emoticon objects. + /// The type of current emoticons. + /// Operating on an ended conversation. + /// Sending custom emoticons from a YIM conversation. + public void SendEmoticonDefinitions(List emoticons, EmoticonType icontype) + { + _type |= ConversationType.Chat; + if (Ended) + { + ReCreate(); + } + + if (conversationState != ConversationState.OneRemoteUserJoined) + { + MessageEnqueue(new EmoticonObject(emoticons, icontype)); + return; + } + + if ((_type & ConversationType.YIM) == ConversationType.YIM) + { + throw new NotSupportedException("YIM conversation not support sending custom emoticons."); + } + + if ((_type & ConversationType.SwitchBoard) == ConversationType.SwitchBoard) + { + _switchboard.SendEmoticonDefinitions(emoticons, icontype); + } + } + + #endregion + + + } +}; diff --git a/MSNPSharp/ConversationID.cs b/MSNPSharp/ConversationID.cs new file mode 100644 index 0000000..0b73e84 --- /dev/null +++ b/MSNPSharp/ConversationID.cs @@ -0,0 +1,200 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace MSNPSharp.Utilities +{ + public class ConversationID + { + private Conversation conversation = null; + private Contact remoteOwner = null; + + private string hashString = string.Empty; + private string compareString = string.Empty; + private int hashCode = 0; + + public Contact RemoteOwner + { + get { return remoteOwner; } + } + + internal Conversation Conversation + { + get + { + return conversation; + } + } + + private object syncObject = new object(); + + internal void SetConversation(Conversation conv) + { + conversation = conv; + if (conversation != null) + { + if (conversation.RemoteOwner == null && RemoteOwner == null) + throw new ArgumentException("Invailid conversation."); + + if (conversation.RemoteOwner != null) + remoteOwner = conversation.RemoteOwner; + } + } + + public ClientType NetworkType + { + get + { + if (!remoteOwner.IsMessengerUser) + return ClientType.None; + + return remoteOwner.ClientType; + } + } + + public ConversationID(Conversation conversation) + { + if (conversation == null) + throw new ArgumentNullException("conversation is null."); + + SetConversation(conversation); + + hashString = ToString(); + hashCode = hashString.GetHashCode(); + + + conversation.ConversationEnded += delegate + { + lock (syncObject) + { + SetConversation(null); + } + }; + + conversation.RemoteOwnerChanged += delegate(object sender, ConversationRemoteOwnerChangedEventArgs args) + { + lock (syncObject) + { + try + { + SetConversation(conversation); + } + catch (Exception) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Remote owner changed to null."); + } + } + }; + } + + public ConversationID(Contact remote) + { + if (remote == null) + throw new ArgumentNullException("remote is null."); + + remoteOwner = remote; + hashString = ToString(); + hashCode = hashString.GetHashCode(); + } + + /// + /// Whether the two conversation are logically equals. + /// + /// + /// + /// + public static bool operator ==(ConversationID id1, object other) + { + if (((object)id1 == null) && other == null) + return true; + + if (((object)id1) == null || other == null) + return false; + + if (other is ConversationID) + { + return id1.Equals(other); + } + + if (other is Conversation) + { + if (id1.conversation == null) return false; + return object.ReferenceEquals(id1.conversation, other); + } + + + return false; + } + + public static bool operator !=(ConversationID id1, object other) + { + return !(id1 == other); + } + + public override bool Equals(object obj) + { + if (object.ReferenceEquals(this, obj)) + return true; + + if (obj == null) + return false; + + if (!(obj is ConversationID)) + return false; + + return ToString() == obj.ToString(); + } + + public override int GetHashCode() + { + return hashCode; + } + + public override string ToString() + { + string remoteOwnerString = (remoteOwner == null ? "null" : remoteOwner.Mail.ToLowerInvariant()); + string conversationString = string.Empty; + if (conversation != null) + { + if ((conversation.Type & ConversationType.MutipleUsers) > 0) + { + conversationString = conversation.Switchboard.SessionHash; + } + } + return string.Join(";", new string[] { NetworkType.ToString().ToLowerInvariant(), remoteOwnerString, conversationString }); + } + } +} diff --git a/MSNPSharp/Core/BitUtility.cs b/MSNPSharp/Core/BitUtility.cs new file mode 100644 index 0000000..21bd571 --- /dev/null +++ b/MSNPSharp/Core/BitUtility.cs @@ -0,0 +1,267 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace MSNPSharp.Core +{ + public static class BitUtility + { + public static short ToInt16(byte[] data, int startIndex, bool dataIsLittleEndian) + { + if (BitConverter.IsLittleEndian == dataIsLittleEndian) + { + return BitConverter.ToInt16(data, startIndex); + } + else + { + return BitConverter.ToInt16(GetSwappedByteArray(data, startIndex, 2), 0); + } + } + + public static ushort ToUInt16(byte[] data, int startIndex, bool dataIsLittleEndian) + { + if (BitConverter.IsLittleEndian == dataIsLittleEndian) + { + return BitConverter.ToUInt16(data, startIndex); + } + else + { + return BitConverter.ToUInt16(GetSwappedByteArray(data, startIndex, 2), 0); + } + } + + public static int ToInt32(byte[] data, int startIndex, bool dataIsLittleEndian) + { + if (BitConverter.IsLittleEndian == dataIsLittleEndian) + { + return BitConverter.ToInt32(data, startIndex); + } + else + { + return BitConverter.ToInt32(GetSwappedByteArray(data, startIndex, 4), 0); + } + } + + public static uint ToUInt32(byte[] data, int startIndex, bool dataIsLittleEndian) + { + if (BitConverter.IsLittleEndian == dataIsLittleEndian) + { + return BitConverter.ToUInt32(data, startIndex); + } + else + { + return BitConverter.ToUInt32(GetSwappedByteArray(data, startIndex, 4), 0); + } + } + + public static long ToInt64(byte[] data, int startIndex, bool dataIsLittleEndian) + { + if (BitConverter.IsLittleEndian == dataIsLittleEndian) + { + return BitConverter.ToInt64(data, startIndex); + } + else + { + return BitConverter.ToInt64(GetSwappedByteArray(data, startIndex, 8), 0); + } + } + + public static ulong ToUInt64(byte[] data, int startIndex, bool dataIsLittleEndian) + { + if (BitConverter.IsLittleEndian == dataIsLittleEndian) + { + return BitConverter.ToUInt64(data, startIndex); + } + else + { + return BitConverter.ToUInt64(GetSwappedByteArray(data, startIndex, 8), 0); + } + } + + + public static byte[] GetBytes(short val, bool littleEndian) + { + byte[] bytes = BitConverter.GetBytes(val); + + if (BitConverter.IsLittleEndian == littleEndian) + return bytes; + + return GetSwappedByteArray(bytes, 0, 2); + } + + public static byte[] GetBytes(ushort val, bool littleEndian) + { + byte[] bytes = BitConverter.GetBytes(val); + + if (BitConverter.IsLittleEndian == littleEndian) + return bytes; + + return GetSwappedByteArray(bytes, 0, 2); + } + + public static byte[] GetBytes(int val, bool littleEndian) + { + byte[] bytes = BitConverter.GetBytes(val); + + if (BitConverter.IsLittleEndian == littleEndian) + return bytes; + + return GetSwappedByteArray(bytes, 0, 4); + } + + public static byte[] GetBytes(uint val, bool littleEndian) + { + byte[] bytes = BitConverter.GetBytes(val); + + if (BitConverter.IsLittleEndian == littleEndian) + return bytes; + + return GetSwappedByteArray(bytes, 0, 4); + } + + public static byte[] GetBytes(long val, bool littleEndian) + { + byte[] bytes = BitConverter.GetBytes(val); + + if (BitConverter.IsLittleEndian == littleEndian) + return bytes; + + return GetSwappedByteArray(bytes, 0, 8); + } + + public static byte[] GetBytes(ulong val, bool littleEndian) + { + byte[] bytes = BitConverter.GetBytes(val); + + if (BitConverter.IsLittleEndian == littleEndian) + return bytes; + + return GetSwappedByteArray(bytes, 0, 8); + } + + private static byte[] GetSwappedByteArray(byte[] data, int startIndex, int length) + { + byte[] swap = new byte[length]; + int endIndex = 0; + while (--length >= 0) + { + swap[length] = data[startIndex + endIndex]; + endIndex++; + } + return swap; + } + + + + + public static ushort ToLittleEndian(ushort val) + { + if (BitConverter.IsLittleEndian) + return val; + + return FlipEndian(val); + } + + public static uint ToLittleEndian(uint val) + { + if (BitConverter.IsLittleEndian) + return val; + + return FlipEndian(val); + } + + public static ulong ToLittleEndian(ulong val) + { + if (BitConverter.IsLittleEndian) + return val; + + return FlipEndian(val); + } + + public static ushort ToBigEndian(ushort val) + { + if (!BitConverter.IsLittleEndian) + return val; + + return FlipEndian(val); + } + + public static uint ToBigEndian(uint val) + { + if (!BitConverter.IsLittleEndian) + return val; + + return FlipEndian(val); + } + + public static ulong ToBigEndian(ulong val) + { + if (!BitConverter.IsLittleEndian) + return val; + + return FlipEndian(val); + } + + private static ushort FlipEndian(ushort val) + { + return (ushort) + (((val & 0x00ff) << 8) + + ((val & 0xff00) >> 8)); + } + + + private static uint FlipEndian(uint val) + { + return (uint) + (((val & 0x000000ff) << 24) + + ((val & 0x0000ff00) << 8) + + ((val & 0x00ff0000) >> 8) + + ((val & 0xff000000) >> 24)); + } + + private static ulong FlipEndian(ulong val) + { + return (ulong) + (((val & 0x00000000000000ff) << 56) + + ((val & 0x000000000000ff00) << 40) + + ((val & 0x0000000000ff0000) << 24) + + ((val & 0x00000000ff000000) << 8) + + ((val & 0x000000ff00000000) >> 8) + + ((val & 0x0000ff0000000000) >> 24) + + ((val & 0x00ff000000000000) >> 40) + + ((val & 0xff00000000000000) >> 56)); + } + } +}; diff --git a/MSNPSharp/Core/Converter.cs b/MSNPSharp/Core/Converter.cs new file mode 100644 index 0000000..5b0ee78 --- /dev/null +++ b/MSNPSharp/Core/Converter.cs @@ -0,0 +1,458 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Web; +using System.Text; +using System.Xml; +using System.Security.Cryptography; + +namespace MSNPSharp.Core +{ + using MSNPSharp.DataTransfer; + + internal enum EscapeType + { + EscapeAll, + EscapeExceptPlus + } + + /// + /// Provides methods for encoding and decoding URLs when processing Web requests. This class cannot be inherited. + /// + public static class MSNHttpUtility + { + private enum UnSafe + { + /// + /// For url encode + /// + UrlEscape = 0x1, + /// + /// For XML encode + /// + XMLEscape = 0x2, + /// + /// For HTML encode + /// + HTMLEscape = 0x4 + } + + private static uint[] ASCII_CLASS; + private static string strUrlUnsafe = " \"#%&+,/:;<=>?@[\\]^`{|}"; + private static string strXmlUnsafe = "&:;<=>?[]\\^{|}"; + private static string strHtmlUnsafe = "&'<> ;\""; + + static MSNHttpUtility() + { + ASCII_CLASS = new uint[256]; + int c = 0; + for (c = 0; c < ASCII_CLASS.Length; c++) + { + if ((c >= 0 && c <= 32) || c >= 126) + { + ASCII_CLASS[c] |= (uint)UnSafe.UrlEscape; + } + + if (c >= 0 && c <= 32) + { + ASCII_CLASS[c] |= (uint)UnSafe.XMLEscape; + } + + if (strUrlUnsafe.IndexOf((char)c) != -1) + { + ASCII_CLASS[c] |= (uint)UnSafe.UrlEscape; + } + if (strXmlUnsafe.IndexOf((char)c) != -1) + { + ASCII_CLASS[c] |= (uint)UnSafe.XMLEscape; + } + if (strHtmlUnsafe.IndexOf((char)c) != -1) + { + ASCII_CLASS[c] |= (uint)UnSafe.HTMLEscape; + } + } + + } + + /// + /// Encodes a MSNObject description using UTF-8 encoding by default. + /// + /// The MSNObject description to encode. + /// An encoded string. + public static string MSNObjectUrlEncode(string str) + { + return UrlEncode(str, Encoding.UTF8, EscapeType.EscapeExceptPlus); + } + + /// + /// Replace space into %20. + /// + /// The string to encode. + /// An encoded string. + public static string NSEncode(string str) + { + return str.Replace(" ", "%20"); + } + + /// + /// Encodes a URL string using UTF-8 encoding by default. + /// + /// The text to encode. + /// An encoded string. + public static string UrlEncode(string str) + { + return UrlEncode(str, Encoding.UTF8, EscapeType.EscapeAll); + } + + /// + /// Encodes a URL string using the specified encoding object. + /// + /// The text to encode. + /// The object that specifies the encoding scheme. + /// An encoded string. + public static string UrlEncode(string str, Encoding e) + { + return UrlEncode(str, e, EscapeType.EscapeAll); + } + + private static string UrlEncode(string str, Encoding e, EscapeType type) + { + if (str == null) + return string.Empty; + byte[] byt = e.GetBytes(str); + StringBuilder result = new StringBuilder(256); + for (int c = 0; c < byt.Length; c++) + { + byte chr = byt[c]; + if ((ASCII_CLASS[chr] & (uint)UnSafe.UrlEscape) != 0) + { + switch (chr) + { + case (byte)'+': + if (type == EscapeType.EscapeAll) + { + result.Append("%20"); + } + else if (type == EscapeType.EscapeExceptPlus) + { + result.Append("%2B"); + } + + break; + default: + result.Append("%" + ((int)chr).ToString("X2")); + break; + + } + } + else + { + result.Append((char)chr); + } + } + + return result.ToString(); + } + + /// + /// Decode an encoded . + /// + /// The encoded MSNObject description. + /// A decoded string. + public static string MSNObjectUrlDecode(string str) + { + return UrlDecode(str, Encoding.UTF8, EscapeType.EscapeExceptPlus); + } + + /// + /// Converts a string that has been encoded for transmission in a URL into a decoded string using UTF-8 encoding by default. + /// + /// The string to decode. + /// A decoded string. + public static string UrlDecode(string str) + { + return UrlDecode(str, Encoding.UTF8, EscapeType.EscapeAll); + } + + /// + /// Converts a URL-encoded string into a decoded string, using the specified encoding object. + /// + /// The string to decode. + /// The that specifies the decoding scheme. + /// A decoded string. + public static string UrlDecode(string str, Encoding e) + { + return UrlDecode(str, e, EscapeType.EscapeAll); + } + + /// + /// Replace "%20" into space. + /// + /// The string to decode. + /// A decoded string. + public static string NSDecode(string str) + { + return str.Replace("%20", " "); + } + + private static string UrlDecode(string str, Encoding e, EscapeType type) + { + if (type == EscapeType.EscapeExceptPlus) + { + return HttpUtility.UrlDecode(str.Replace("%2b", "+").Replace("%2B", "+"), e); + } + + return HttpUtility.UrlDecode(str.Replace("%20", "+"), e); + } + + /// + /// Encodes a Xml string. + /// + /// The string to decode. + /// A decoded string. + public static string XmlEncode(string str) + { + if (str == null) + return string.Empty; + + char[] chrArr = str.ToCharArray(); + char chr; + StringBuilder result = new StringBuilder(256); + for (int c = 0; c < chrArr.Length; c++) + { + chr = chrArr[c]; + + if (chr < 128) + { + if ((ASCII_CLASS[chr] & (uint)UnSafe.XMLEscape) != 0) + { + result.Append("&#x" + ((int)chr).ToString("X2") + ";"); + continue; + } + } + + result.Append(chr); + } + + return result.ToString(); + } + + + /// + /// Decode the QP encoded string. + /// + /// The string to decode. + /// A decoded string. + public static string QPDecode(string str) + { + return QPDecode(str, Encoding.Default); + } + + /// + /// Decode the QP encoded string using an encoding + /// + /// The string to decode. + /// The that specifies the decoding scheme. + /// A decoded string. + public static string QPDecode(string value, Encoding encode) + { + string inputString = value; + StringBuilder builder1 = new StringBuilder(); + inputString = inputString.Replace("=\r\n", ""); + for (int num1 = 0; num1 < inputString.Length; num1++) + { + if (inputString[num1] == '=') + { + try + { + if (HexToDec(inputString.Substring(num1 + 1, 2)) < 0x80) + { + if (HexToDec(inputString.Substring(num1 + 1, 2)) >= 0) + { + byte[] buffer1 = new byte[1] { (byte)HexToDec(inputString.Substring(num1 + 1, 2)) }; + builder1.Append(encode.GetString(buffer1)); + num1 += 2; + } + } + else if (inputString[num1 + 1] != '=') + { + byte[] buffer2 = new byte[2] { (byte)HexToDec(inputString.Substring(num1 + 1, 2)), (byte)HexToDec(inputString.Substring(num1 + 4, 2)) }; + builder1.Append(encode.GetString(buffer2)); + num1 += 5; + } + } + catch + { + builder1.Append(inputString.Substring(num1, 1)); + } + } + else + { + builder1.Append(inputString.Substring(num1, 1)); + } + } + return builder1.ToString(); + } + + private static int HexToDec(string hex) + { + int num1 = 0; + string text1 = "0123456789ABCDEF"; + for (int num2 = 0; num2 < hex.Length; num2++) + { + if (text1.IndexOf(hex[num2]) == -1) + { + return -1; + } + num1 = (num1 * 0x10) + text1.IndexOf(hex[num2]); + } + return num1; + } + + + public static int IndexOf(byte[] input, byte[] pattern) + { + if (pattern.Length > input.Length) + return -1; + + for (int i = 0; i <= input.Length - pattern.Length; i++) + { + bool found = true; + + for (int j = 0; j < pattern.Length; j++) + { + if (input[i + j] != pattern[j]) + { + found = false; + break; + } + } + + if (found) + return i; + } + + return -1; + } + + public static int IndexOf(byte[] input, string pattern) + { + return IndexOf(input, Encoding.UTF8.GetBytes(pattern)); + } + } + + public static class WebServiceDateTimeConverter + { + /// + /// Convert the XML time to .net instance. + /// + /// + /// + public static DateTime ConvertToDateTime(string dateTime) + { + if (dateTime == null || dateTime == string.Empty) + dateTime = WebServiceConstants.ZeroTime; + + return XmlConvert.ToDateTime(dateTime, WebServiceConstants.XmlDateTimeFormats); + } + } + + + public static class HashedNonceGenerator + { + /// + /// Creates handshake guid using SHA1 hash algorithm. + /// + /// + /// The output packed to handshake for direct connect + public static Guid HashNonce(Guid nonce) + { + // http://forums.fanatic.net.nz/index.php?showtopic=19372&view=findpost&p=108868 + // {2B95F56D-9CA0-9A64-82CE-ADC1F3C55845} <-> [0x37,0x29,0x2d,0x12,0x86,0x5c,0x7b,0x4c,0x81,0xf5,0xe,0x5,0x1,0x78,0x80,0xc2] + // OUTPUT: 2b95f56d-9ca0-9a64-82ce-adc1f3c55845 + // INPUT: 122d2937-5c86-4c7b-81f5-0e05017880c2 + + Guid handshakeNonce = Guid.Empty; + + using (SHA1Managed sha1 = new SHA1Managed()) + { + // Returns 20 bytes + byte[] hash = sha1.ComputeHash(nonce.ToByteArray()); + + handshakeNonce = CreateGuidFromData(P2PVersion.P2PV2, hash); + } + + return handshakeNonce; + } + + + public static Guid CreateGuidFromData(P2PVersion ver, byte[] data) + { + Guid ret = Guid.Empty; + + if (ver == P2PVersion.P2PV1) + { + P2PMessage message = new P2PMessage(ver); + message.ParseBytes(data); + + ret = new Guid( + (int)message.V1Header.AckSessionId, + + (short)(message.Header.AckIdentifier & 0x0000FFFF), + (short)((message.Header.AckIdentifier & 0xFFFF0000) >> 16), + + (byte)((message.V1Header.AckTotalSize & 0x00000000000000FF)), + (byte)((message.V1Header.AckTotalSize & 0x000000000000FF00) >> 8), + (byte)((message.V1Header.AckTotalSize & 0x0000000000FF0000) >> 16), + (byte)((message.V1Header.AckTotalSize & 0x00000000FF000000) >> 24), + (byte)((message.V1Header.AckTotalSize & 0x000000FF00000000) >> 32), + (byte)((message.V1Header.AckTotalSize & 0x0000FF0000000000) >> 40), + (byte)((message.V1Header.AckTotalSize & 0x00FF000000000000) >> 48), + (byte)((message.V1Header.AckTotalSize & 0xFF00000000000000) >> 56) + ); + } + else if (ver == P2PVersion.P2PV2) + { + Int32 a = BitUtility.ToInt32(data, 0, BitConverter.IsLittleEndian); + Int16 b = BitUtility.ToInt16(data, 4, BitConverter.IsLittleEndian); + Int16 c = BitUtility.ToInt16(data, 6, BitConverter.IsLittleEndian); + byte d = data[8], e = data[9], f = data[10], g = data[11]; + byte h = data[12], i = data[13], j = data[14], k = data[15]; + + ret = new Guid(a, b, c, d, e, f, g, h, i, j, k); + } + + return ret; + } + } +}; \ No newline at end of file diff --git a/MSNPSharp/Core/IMessageHandler.cs b/MSNPSharp/Core/IMessageHandler.cs new file mode 100644 index 0000000..7d051d0 --- /dev/null +++ b/MSNPSharp/Core/IMessageHandler.cs @@ -0,0 +1,64 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; + +namespace MSNPSharp.Core +{ + /// + /// IMessageHandler defines the methods required to handle incoming network messages. + /// + public interface IMessageHandler + { + /// + /// Gets or sets the processor of network messages. + /// Every message handler is associated with a single message processor. + /// This way the handler can initiate, or send, messages which are not a reply + /// on incoming messages. + /// + IMessageProcessor MessageProcessor + { + get; + set; + } + + /// + /// A IMessageProcessor calls this method. The handler can then process the + /// message. + /// + /// + /// + /// + /// + void HandleMessage(IMessageProcessor sender, NetworkMessage message); + } +}; diff --git a/MSNPSharp/Core/MSNMessage.cs b/MSNPSharp/Core/MSNMessage.cs new file mode 100644 index 0000000..4a70b78 --- /dev/null +++ b/MSNPSharp/Core/MSNMessage.cs @@ -0,0 +1,254 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Text; +using System.Collections; +using System.Globalization; + +namespace MSNPSharp.Core +{ + using MSNPSharp; + + [Serializable()] + public class MSNMessage : NetworkMessage, ICloneable + { + protected int transactionID = -1; + private string command = "MSG"; + private ArrayList commandValues; + private const string noTransactionIDCommands = "OUT PNG QNG RNG"; + + public MSNMessage() + { + commandValues = new ArrayList(); + } + + public MSNMessage(string command, ArrayList commandValues) + { + Command = command; + CommandValues = commandValues; + } + + public override void PrepareMessage() + { + base.PrepareMessage(); + } + + + public int TransactionID + { + get + { + return transactionID; + } + set + { + transactionID = value; + } + } + + public string Command + { + get + { + return command; + } + set + { + command = value; + } + } + + public ArrayList CommandValues + { + get + { + return commandValues; + } + set + { + commandValues = value; + } + } + + public override byte[] GetBytes() + { + + StringBuilder builder = new StringBuilder(128); + builder.Append(Command); + + if (noTransactionIDCommands.IndexOf(Command) == -1) + { + if (TransactionID != -1) + { + builder.Append(' '); + builder.Append(TransactionID.ToString(CultureInfo.InvariantCulture)); + } + } + + foreach (string val in CommandValues) + { + builder.Append(' '); + builder.Append(val); + } + + + + if (InnerMessage != null) + { + builder.Append(' '); + builder.Append(InnerMessage.GetBytes().Length); + builder.Append("\r\n"); + return AppendArray(System.Text.Encoding.UTF8.GetBytes(builder.ToString()), InnerMessage.GetBytes()); + } + else + { + builder.Append("\r\n"); + return System.Text.Encoding.UTF8.GetBytes(builder.ToString()); + } + } + + public override void ParseBytes(byte[] data) + { + + int cnt = 0; + int bodyStart = 0; + + while (data[cnt] != '\r') + { + cnt++; + + // watch out for buffer overflow + if (cnt == data.Length) + throw new MSNPSharpException("Parsing of incoming command message failed. No newline was detected."); + } + + bodyStart = cnt + 1; + while (bodyStart < data.Length && (data[bodyStart] == '\r' || data[bodyStart] == '\n')) + { + bodyStart++; + } + + // get the command parameters + Command = System.Text.Encoding.UTF8.GetString(data, 0, 3); + string commandLine = Encoding.UTF8.GetString(data, 4, cnt - 4); + CommandValues = new ArrayList(commandLine.Split(new char[] { ' ' })); + + + //Filter those commands follow by a number but not transaction id. + if (noTransactionIDCommands.IndexOf(Command) == -1) + { + if (CommandValues.Count > 0) + { + if (!int.TryParse((string)CommandValues[0], out transactionID)) + { + transactionID = -1; //if there's no transid, set to -1 + } + else + { + CommandValues.RemoveAt(0); + } + } + + } + + // set the inner body contents, if it is available + if (bodyStart < data.Length) + { + if (CommandValues.Count > 0) + { + CommandValues.RemoveAt(CommandValues.Count - 1); + } + + int startIndex = bodyStart; + int newLength = data.Length - startIndex; + InnerBody = new byte[newLength]; + Array.Copy(data, startIndex, InnerBody, 0, newLength); + } + + + } + + /// + /// Get the debug string representation of the message + /// + /// + /// + /// To futher developers: + /// You cannot simply apply Encoding.UTF8.GetString(GetByte()) in this function + /// since the InnerMessage of MSNMessage may contain binary data. + /// + public override string ToString() + { + StringBuilder builder = new StringBuilder(128); + builder.Append(Command); + + + if (noTransactionIDCommands.IndexOf(Command) == -1) + { + if (TransactionID != -1) + { + builder.Append(' '); + builder.Append(TransactionID.ToString(CultureInfo.InvariantCulture)); + } + } + + + foreach (string val in CommandValues) + { + builder.Append(' '); + builder.Append(val); + } + + + if (InnerMessage != null) + { + builder.Append(' '); + builder.Append(InnerMessage.GetBytes().Length); + } + + //For toString, we do not return the inner message's string. + return builder.ToString(); + } + + #region ICloneable Member + + object ICloneable.Clone() + { + MSNMessage messageClone = new MSNMessage(); + messageClone.ParseBytes(GetBytes()); + return messageClone; + } + + #endregion + } +}; diff --git a/MSNPSharp/Core/MessagePool.cs b/MSNPSharp/Core/MessagePool.cs new file mode 100644 index 0000000..0290d7f --- /dev/null +++ b/MSNPSharp/Core/MessagePool.cs @@ -0,0 +1,78 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; + +namespace MSNPSharp.Core +{ + using MSNPSharp; + + /// + /// Stores incoming messages in a buffer and releases them only when all contents are received. + /// + /// + /// MessagePool buffers incoming raw byte data and releases this data only when the message is fully retrieved. + /// This supports when a single message is send in multiple packets. + /// The descendants of this class have simple knowledge of the used protocol to identify whether a message is fully retrieved or not. + /// + public abstract class MessagePool + { + /// + /// Constructor to instantiate a message pool. + /// + protected MessagePool() + { + } + + /// + /// Defines whether there is a message available to retrieve. + /// + public abstract bool MessageAvailable + { + get; + } + + /// + /// Buffers the incoming raw data internal. This method is often used after receiving incoming data from a socket or another source. + /// + /// + public abstract void BufferData(BinaryReader reader); + + + /// + /// Retrieves the next message data from the buffer. + /// + /// + public abstract byte[] GetNextMessageData(); + } +}; diff --git a/MSNPSharp/Core/MessageProcessor.cs b/MSNPSharp/Core/MessageProcessor.cs new file mode 100644 index 0000000..b826156 --- /dev/null +++ b/MSNPSharp/Core/MessageProcessor.cs @@ -0,0 +1,69 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; + +namespace MSNPSharp.Core +{ + using MSNPSharp; + + /// + /// Defines methods to send network messages. + /// + /// + /// IMessageProcessor is the abstraction of an object which can send network messages. + /// Network messages can be any kind of messages: text messages, data messages. + /// By using this interface a de-coupling is established between the handling of messages + /// and the I/O of messages. + /// IMessageProcessor is mostly used internal. + /// + public interface IMessageProcessor + { + /// + /// Sends a message to be processed by the processor. + /// + /// + void SendMessage(NetworkMessage message); + + /// + /// Registers a handler that wants to receive incoming messages. + /// + /// + void RegisterHandler(IMessageHandler handler); + + /// + /// Unregisters (removes) a handler that no lange wants to receive incoming messages. + /// + /// + void UnregisterHandler(IMessageHandler handler); + } +}; diff --git a/MSNPSharp/Core/MimeDictionary.cs b/MSNPSharp/Core/MimeDictionary.cs new file mode 100644 index 0000000..4310595 --- /dev/null +++ b/MSNPSharp/Core/MimeDictionary.cs @@ -0,0 +1,236 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace MSNPSharp.Core +{ + public class MimeDictionary : SortedList + { + public new MimeValue this[string name] + { + get + { + if (!ContainsKey(name)) + return new MimeValue(); + + return (MimeValue)base[name]; + } + set + { + base[name] = value; + } + } + + public MimeDictionary() + { + } + + public MimeDictionary(byte[] data) + { + Parse(data); + } + + public int Parse(byte[] data) + { + int end = MSNHttpUtility.IndexOf(data, "\r\n\r\n"); + int ret = end; + + if (end < 0) + ret = end = data.Length; + else + ret += 4; + + byte[] mimeData = new byte[end]; + Array.Copy(data, mimeData, end); + + string mimeStr = Encoding.UTF8.GetString(mimeData); + string[] lines = mimeStr.Trim().Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + + int i = 0; + while (i < lines.Length) + { + string line = lines[i]; + + while ((++i < lines.Length) && lines[i].StartsWith("\t")) + line += lines[i]; + + int nameEnd = line.IndexOf(":"); + + if (nameEnd < 0) + continue; + + string name = line.Substring(0, nameEnd).Trim(); + MimeValue val = line.Substring(nameEnd + 1).Trim(); + + this[name] = val; + } + + return ret; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + + foreach (KeyValuePair pair in this) + { + sb.Append(pair.Key).Append(": ").Append(pair.Value.ToString()).Append("\r\n"); + } + + return sb.ToString(); + } + } + + public class MimeValue + { + string _val; + SortedList _attributes = new SortedList(); + + public string Value + { + get + { + return _val; + } + } + + MimeValue(string main, SortedList attributes) + { + if (attributes == null) + throw new ArgumentNullException("attributes"); + + _val = main; + _attributes = attributes; + } + + public MimeValue(string main) + { + _val = main; + } + + public MimeValue() + { + _val = string.Empty; + } + + public string this[object attKey] + { + get + { + if (!_attributes.ContainsKey(attKey)) + return string.Empty; + + return _attributes[attKey].ToString(); + } + set + { + _attributes[attKey] = value; + } + } + + public static implicit operator string(MimeValue val) + { + return val.ToString(); + } + + public static implicit operator MimeValue(string str) + { + if (str == null) + str = string.Empty; + + str = str.Trim(); + + string main = str; + SortedList attributes = new SortedList(); + + if (main.Contains(";")) + { + main = main.Substring(0, main.IndexOf(";")).Trim(); + str = str.Substring(str.IndexOf(";") + 1); + + string[] parameters = str.Split(';'); + + int i = 0; + foreach (string param in parameters) + { + int index = param.IndexOf('='); + + object key = i++; + string val = param; //string.Empty; + + if (index > 0) + { + key = param.Substring(0, index).Trim(); + val = param.Substring(index + 1).Trim(); + } + else + { + + } + + attributes[key] = val; + } + } + + return new MimeValue(main, attributes); + } + + public void ClearAttributes() + { + _attributes.Clear(); + } + + public bool HasAttribute(string name) + { + return _attributes.ContainsKey(name); + } + + public override string ToString() + { + string str = _val; + + foreach (KeyValuePair att in _attributes) + { + if (!string.IsNullOrEmpty(str)) + str += ";"; + + str += (att.Key is int) ? att.Value : String.Format("{0}={1}", att.Key, att.Value); + } + + return str.Trim(); + } + } +}; diff --git a/MSNPSharp/Core/MimeMessage.cs b/MSNPSharp/Core/MimeMessage.cs new file mode 100644 index 0000000..db4bf8a --- /dev/null +++ b/MSNPSharp/Core/MimeMessage.cs @@ -0,0 +1,193 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Text; +using System.Collections; +using System.Collections.Generic; + +namespace MSNPSharp.Core +{ + using MSNPSharp; + using MSNPSharp.DataTransfer; + + /// + /// Message with MIME headers. + /// + [Serializable()] + public class MimeMessage : NetworkMessage + { + StrDictionary mimeHeader; + + public MimeMessage() + { + mimeHeader = new StrDictionary(); + MimeHeader.Add("MIME-Version", "1.0"); + } + + public MimeMessage(bool autoAppendHeaderVersion) + { + mimeHeader = new StrDictionary(); + + if (autoAppendHeaderVersion) + MimeHeader.Add("MIME-Version", "1.0"); + } + + public StrDictionary MimeHeader + { + get + { + return mimeHeader; + } + } + + public override byte[] GetBytes() + { + StringBuilder builder = new StringBuilder(); + + foreach (StrKeyValuePair entry in MimeHeader) + builder.Append(entry.Key).Append(": ").Append(entry.Value).Append("\r\n"); + + builder.Append("\r\n"); + + if (InnerMessage != null) + return AppendArray(System.Text.Encoding.UTF8.GetBytes(builder.ToString()), InnerMessage.GetBytes()); + + return System.Text.Encoding.UTF8.GetBytes(builder.ToString()); + } + + protected static StrDictionary ParseMime(IEnumerator enumerator, byte[] data) + { + StrDictionary table = new StrDictionary(); + + string name = null; + string val = null; + + int startpos = 0; + int endpos = 0; + bool gettingval = false; + + while (enumerator.MoveNext()) + { + if ((byte)enumerator.Current == 13) + { + // no name specified -> end of header (presumably \r\n\r\n) + if (startpos == endpos && !gettingval) + { + enumerator.MoveNext(); + return table; + } + + val = Encoding.UTF8.GetString(data, startpos, endpos - startpos); + + if (!table.ContainsKey(name)) + table.Add(name, val); + + startpos = endpos + 2; + gettingval = false; + } + else if ((byte)enumerator.Current == 58) //: + { + if (!gettingval) + { + gettingval = true; + name = Encoding.UTF8.GetString(data, startpos, endpos - startpos); + startpos = endpos + 2; + enumerator.MoveNext(); + endpos++; + } + } + endpos++; + } + + return table; + } + + public override void ParseBytes(byte[] data) + { + // parse the header + IEnumerator enumerator = data.GetEnumerator(); + mimeHeader = ParseMime(enumerator, data); + + // get the rest of the message + MemoryStream memStream = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(memStream); + while (enumerator.MoveNext()) + writer.Write((byte)enumerator.Current); + InnerBody = memStream.ToArray(); + memStream.Close(); + } + + + public override string ToString() + { + StringBuilder builder = new StringBuilder(); + foreach (StrKeyValuePair entry in MimeHeader) + { + builder.Append(entry.Key).Append(": ").Append(entry.Value).Append("\r\n"); + } + builder.Append("\r\n"); + return builder.ToString(); + } + } + + + public class P2PMimeMessage : MimeMessage + { + public P2PMimeMessage(string destString, string srcString, NetworkMessage payLoad) + :base() + { + MimeHeader["P2P-Dest"] = destString; + MimeHeader["P2P-Src"] = srcString; + MimeHeader[MimeHeaderStrings.Content_Type] = "application/x-msnmsgrp2p"; + + InnerMessage = payLoad; + } + + public override byte[] GetBytes() + { + return base.GetBytes(); + } + + public override void ParseBytes(byte[] data) + { + base.ParseBytes(data); + } + + public override string ToString() + { + return base.ToString(); + } + } + +}; diff --git a/MSNPSharp/Core/NSMessage.cs b/MSNPSharp/Core/NSMessage.cs new file mode 100644 index 0000000..bd024de --- /dev/null +++ b/MSNPSharp/Core/NSMessage.cs @@ -0,0 +1,105 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Text; +using System.Collections; + +namespace MSNPSharp.Core +{ + using MSNPSharp; + + [Serializable()] + public class NSMessage : MSNMessage, ICloneable + { + public NSMessage() + : base() + { + } + + public NSMessage(string command, ArrayList commandValues) + : base(command, commandValues) + { + } + + public NSMessage(string command, string[] commandValues) + : base(command, new ArrayList(commandValues)) + { + } + + public NSMessage(string command) + : base() + { + Command = command; + } + + /// + /// + /// + /// + public override byte[] GetBytes() + { + switch (Command) + { + case "PNG": + return System.Text.Encoding.UTF8.GetBytes("PNG\r\n"); + + default: + return base.GetBytes(); + + } + } + + public override string ToString() + { + return base.ToString(); + } + + #region ICloneable Ա + + object ICloneable.Clone() + { + NSMessage messageClone = new NSMessage(); + messageClone.ParseBytes(GetBytes()); + + if (messageClone.InnerBody == null && InnerBody != null) + { + messageClone.InnerBody = new byte[InnerBody.Length]; + Array.Copy(InnerBody, messageClone.InnerBody, InnerBody.Length); + } + + return messageClone; + } + + #endregion + } +}; diff --git a/MSNPSharp/Core/NSMessagePool.cs b/MSNPSharp/Core/NSMessagePool.cs new file mode 100644 index 0000000..9b2ec89 --- /dev/null +++ b/MSNPSharp/Core/NSMessagePool.cs @@ -0,0 +1,290 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; + +namespace MSNPSharp.Core +{ + using MSNPSharp; + + /// + /// Buffers the incoming data from the notification server (NS). + /// + /// + /// The main purpose of this class is to ensure that MSG, IPG and NOT payload commands are processed + /// only when they are complete. Payload commands can be quite large and may be larger + /// than the socket buffer. This pool will buffer the data and release the messages, or commands, + /// when they are fully retrieved from the server. + /// + public class NSMessagePool : MessagePool, IDisposable + { + Queue messageQueue = new Queue(); + MemoryStream bufferStream; + BinaryWriter bufferWriter; + int remainingBuffer; + + public NSMessagePool() + { + CreateNewBuffer(); + } + + ~NSMessagePool() + { + Dispose(false); + } + + /// + /// Is true when there are message available to retrieve. + /// + public override bool MessageAvailable + { + get + { + return messageQueue.Count > 0; + } + } + + protected Queue MessageQueue + { + get + { + return messageQueue; + } + } + + /// + /// This points to the current message we are writing to. + /// + protected MemoryStream BufferStream + { + get + { + return bufferStream; + } + set + { + bufferStream = value; + } + } + + /// + /// This is the interface to the bufferStream. + /// + protected BinaryWriter BufferWriter + { + get + { + return bufferWriter; + } + set + { + bufferWriter = value; + } + } + + /// + /// Creates a new memorystream to server as the buffer. + /// + private void CreateNewBuffer() + { + bufferStream = new MemoryStream(64); + bufferWriter = new BinaryWriter(bufferStream); + } + + /// + /// Enques the current buffer memorystem when a message is completely retrieved. + /// + private void EnqueueCurrentBuffer() + { + messageQueue.Enqueue(bufferStream); + } + + /// + /// Get the next message as a byte array. The returned data includes all newlines which seperate the commands ("\r\n") + /// + /// + public override byte[] GetNextMessageData() + { + return messageQueue.Dequeue().ToArray(); + } + + /// + /// Stores the raw data in a buffer. When a full message is detected it is inserted on the internal stack. + /// You can retrieve these messages bij calling GetNextMessageData(). + /// + /// + public override void BufferData(BinaryReader reader) + { + int length = (int)(reader.BaseStream.Length - reader.BaseStream.Position); + + // there is nothing in the bufferstream so we expect a command right away + while (length > 0) + { + // should we buffer the current message + if (remainingBuffer > 0) + { + // read as much as possible in the current message stream + int readLength = Math.Min(remainingBuffer, length); + byte[] msgBuffer = reader.ReadBytes(readLength); + bufferStream.Write(msgBuffer, 0, msgBuffer.Length); + + // subtract what we have read from the total length + remainingBuffer -= readLength; + length = (int)(reader.BaseStream.Length - reader.BaseStream.Position); + + // when we have read everything we can start a new message + if (remainingBuffer == 0) + { + EnqueueCurrentBuffer(); + CreateNewBuffer(); + } + } + else + { + // read until we come across a newline + byte val = reader.ReadByte(); + + if (val != '\n') + bufferWriter.Write(val); + else + { + // write the last newline + bufferWriter.Write(val); + + // check if it's a payload command + bufferStream.Position = 0; + string cmd3 = System.Text.Encoding.ASCII.GetString(new byte[3] { + (byte)bufferStream.ReadByte(), + (byte)bufferStream.ReadByte(), + (byte)bufferStream.ReadByte() + }); + + switch (cmd3) + { + case "MSG": // MSG payload command + case "NOT": // NOT notification command + case "GCF": // GCF privacy settings + case "UBN": // UBN Unified Budy Notification (for SIP requests) + case "FQY": // FQY Federated QuerY command + case "DEL": // DEL + case "GET": // GET + case "PUT": // PUT + case "NFY": // NFY + case "SDG": // SDG circle messaging + case "IPG": // IPG pager command + case "UBX": // UBX personal message + case "UBM": // UBM Yahoo messenger message + case "UUN": // UUN Unified User Notification + case "ADL": // ADL Add List command + case "RML": // RML Remove List command + case "203": // 203 + case "204": // 204 Invalid contact network in ADL/RML + case "205": // 205 + case "210": // 210 + case "234": // 234 + case "241": // 241 Invalid membership for ADL/RML + case "508": // 508 + case "509": // 509 UpsFailure, when sending mobile message + case "511": // 511 + case "933": // 933 + { + bufferStream.Seek(-3, SeekOrigin.End); + + // calculate the length by reading backwards from the end + remainingBuffer = 0; + int size = 0; + + for (int i = 0; ((size = bufferStream.ReadByte()) > 0) && size >= '0' && size <= '9'; i++) + { + remainingBuffer += (int)((size - '0') * Math.Pow(10, i)); + bufferStream.Seek(-2, SeekOrigin.Current); + } + + // move to the end of the stream before we are going to write + bufferStream.Seek(0, SeekOrigin.End); + + if (remainingBuffer == 0) + { + EnqueueCurrentBuffer(); + CreateNewBuffer(); + } + } + break; + + default: + { + // it was just a plain command start a new message + EnqueueCurrentBuffer(); + CreateNewBuffer(); + } + break; + } + + } + length--; + } + } + } + + #region IDisposable Members + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + // Dispose managed resources + if (bufferWriter != null) + ((IDisposable)bufferWriter).Dispose(); + + if (bufferStream != null) + bufferStream.Dispose(); + + if (messageQueue.Count > 0) + messageQueue.Clear(); + } + + // Free native resources + } + + + #endregion + } +}; diff --git a/MSNPSharp/Core/NSPayLoadMessage.cs b/MSNPSharp/Core/NSPayLoadMessage.cs new file mode 100644 index 0000000..b2db112 --- /dev/null +++ b/MSNPSharp/Core/NSPayLoadMessage.cs @@ -0,0 +1,134 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections; +using System.Globalization; + +namespace MSNPSharp.Core +{ + /// + /// NS payload message class, such as ADL and FQY + /// The format of these mseeages is: COMMAND TRANSID [PARAM1] [PARAM2] .. PAYLOADLENGTH\r\nPAYLOAD + /// + /// DONOT pass the payload length as command value, the payload length will be calculated automatically + /// + /// + /// List of NS payload commands: + /// + /// RML + /// Remove contact + /// + /// + /// ADL + /// Add users to your contact lists. + /// + /// + /// FQY + /// Query client's network types except PassportMember + /// + /// + /// QRY + /// Response to CHL by client + /// + /// NOT + /// UBX + /// GCF + /// IPG + /// UUX + /// MSG + /// UBN + /// + /// + /// + /// + [Serializable()] + public class NSPayLoadMessage : NSMessage + { + private string payLoad = string.Empty; + + public string PayLoad + { + get + { + if (InnerMessage == null) + return string.Empty; + else + { + return (InnerMessage as TextPayloadMessage).Text; + } + } + } + + public NSPayLoadMessage() + : base() + { + + } + + public NSPayLoadMessage(string command, ArrayList commandValues, string payload) + : base(command, commandValues) + { + InnerMessage = new TextPayloadMessage(payload); + } + + public NSPayLoadMessage(string command, string[] commandValues, string payload) + : base(command, new ArrayList(commandValues)) + { + InnerMessage = new TextPayloadMessage(payload); + } + + public NSPayLoadMessage(string command, string payload) + : base(command) + { + InnerMessage = new TextPayloadMessage(payload); + } + + public override void ParseBytes(byte[] data) + { + base.ParseBytes(data); + } + + public override byte[] GetBytes() + { + return base.GetBytes(); + } + + public override string ToString() + { + return base.ToString(); + } + + } +}; diff --git a/MSNPSharp/Core/NetworkMessage.cs b/MSNPSharp/Core/NetworkMessage.cs new file mode 100644 index 0000000..1e6cc45 --- /dev/null +++ b/MSNPSharp/Core/NetworkMessage.cs @@ -0,0 +1,148 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; + +namespace MSNPSharp.Core +{ + using MSNPSharp; + + public abstract class NetworkMessage + { + byte[] innerBody; + NetworkMessage parentMessage; + NetworkMessage innerMessage; + + protected NetworkMessage() + { + } + + public virtual void CreateFromParentMessage(NetworkMessage containerMessage) + { + ParentMessage = containerMessage; + ParentMessage.InnerMessage = this; + + if (ParentMessage.InnerBody != null) + ParseBytes(ParentMessage.InnerBody); + } + + protected virtual void OnInnerMessageSet() + { + if (InnerMessage != null && InnerMessage.ParentMessage != this) + InnerMessage.ParentMessage = this; + } + + protected virtual void OnParentMessageSet() + { + if (ParentMessage != null && ParentMessage.InnerMessage != this) + ParentMessage.InnerMessage = this; + } + + /// + /// The byte array contains in the message stream + /// + public byte[] InnerBody + { + get + { + return innerBody; + } + set + { + innerBody = value; + } + } + + /// + /// Usually the payload of a payload message. + /// + public NetworkMessage InnerMessage + { + get + { + return innerMessage; + } + set + { + innerMessage = value; + OnInnerMessageSet(); + } + } + + public NetworkMessage ParentMessage + { + get + { + return parentMessage; + } + set + { + parentMessage = value; + OnParentMessageSet(); + } + } + + /// + /// Format the message and make it ready to send. + /// + public virtual void PrepareMessage() + { + if (InnerMessage != null) + InnerMessage.PrepareMessage(); + } + + public abstract byte[] GetBytes(); + public abstract void ParseBytes(byte[] data); + + public string ToDebugString() + { + if (InnerMessage != null) + return ToString() + "\r\n" + InnerMessage.ToDebugString(); + else + return ToString(); + } + + public static byte[] AppendArray(byte[] originalArray, byte[] appendingArray) + { + if (appendingArray != null) + { + byte[] newArray = new byte[originalArray.Length + appendingArray.Length]; + Array.Copy(originalArray, 0, newArray, 0, originalArray.Length); + Array.Copy(appendingArray, 0, newArray, originalArray.Length, appendingArray.Length); + return newArray; + } + else + return originalArray; + } + + } +}; diff --git a/MSNPSharp/Core/NotificationMessage.cs b/MSNPSharp/Core/NotificationMessage.cs new file mode 100644 index 0000000..d49ffca --- /dev/null +++ b/MSNPSharp/Core/NotificationMessage.cs @@ -0,0 +1,528 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Xml; +using System.Text; +using System.Diagnostics; +using System.Globalization; + +namespace MSNPSharp.Core +{ + /// + /// Represents a single NOT or IPG message. + /// + /// + /// These messages are receid from, and send to, a nameserver. NOT messages are rececived for MSN-Calendar or MSN-Alert notifications. + /// IPG commands are received/send to exchange pager (sms) messages. + /// + [Serializable()] + public class NotificationMessage : MSNMessage + { + /// + /// Constructor. + /// + public NotificationMessage() + { + } + + /// + /// Constructs a NotificationMessage from the inner body contents of the specified message object. + /// This will also set the InnerMessage property of the message object to the newly created NotificationMessage. + /// + public NotificationMessage(NetworkMessage message) + { + ParseBytes(message.InnerBody); + message.InnerMessage = this; + } + /* Example notification + * \r\n + \r\n + \r\n + \r\n + \r\n + \r\n + goto club 7. 2002 21:15 - 22:15 \r\n + \r\n + \r\n + \r\n + */ + + #region Private + + private bool notificationTypeSpecified = false; + + public bool NotificationTypeSpecified + { + get { return notificationTypeSpecified; } + set { notificationTypeSpecified = value; } + } + + /// + /// + NotificationType notificationType = NotificationType.Alert; + + public NotificationType NotificationType + { + get { return notificationType; } + set { notificationType = value; } + } + + private int id = 0; + + public int Id + { + get { return id; } + set { id = value; } + } + private int siteId = 0; + + public int SiteId + { + get { return siteId; } + set { siteId = value; } + } + private string siteUrl = string.Empty; + + public string SiteUrl + { + get { return siteUrl; } + set { siteUrl = value; } + } + + private string receiverAccount = string.Empty; + + public string ReceiverAccount + { + get { return receiverAccount; } + set { receiverAccount = value; } + } + private string receiverOfflineMail = string.Empty; + + public string ReceiverOfflineMail + { + get { return receiverOfflineMail; } + set { receiverOfflineMail = value; } + } + private string receiverMemberIdLow = string.Empty; + + public string ReceiverMemberIdLow + { + get { return receiverMemberIdLow; } + set { receiverMemberIdLow = value; } + } + private string receiverMemberIdHigh = string.Empty; + + public string ReceiverMemberIdHigh + { + get { return receiverMemberIdHigh; } + set { receiverMemberIdHigh = value; } + } + + private string senderAccount = string.Empty; + + public string SenderAccount + { + get { return senderAccount; } + set { senderAccount = value; } + } + private string senderMemberIdLow = string.Empty; + + public string SenderMemberIdLow + { + get { return senderMemberIdLow; } + set { senderMemberIdLow = value; } + } + private string senderMemberIdHigh = string.Empty; + + public string SenderMemberIdHigh + { + get { return senderMemberIdHigh; } + set { senderMemberIdHigh = value; } + } + + private string sendDevice = string.Empty; + + public string SendDevice + { + get { return sendDevice; } + set { sendDevice = value; } + } + + private int messageId = 0; + + public int MessageId + { + get { return messageId; } + set { messageId = value; } + } + + private string pri = string.Empty; + + public string Pri + { + get { return pri; } + set { pri = value; } + } + + private string actionUrl = string.Empty; + + public string ActionUrl + { + get { return actionUrl; } + set { actionUrl = value; } + } + private string subcriptionUrl = string.Empty; + + public string SubcriptionUrl + { + get { return subcriptionUrl; } + set { subcriptionUrl = value; } + } + + private string catId = "110110001"; + + public string CatId + { + get { return catId; } + set { catId = value; } + } + + private string language = string.Empty; + + public string Language + { + get { return language; } + set { language = value; } + } + + private string iconUrl = string.Empty; + + public string IconUrl + { + get { return iconUrl; } + set { iconUrl = value; } + } + + private string text = string.Empty; + + public string Text + { + get { return text; } + set { text = value; } + } + private string offlineText = string.Empty; + + public string OfflineText + { + get { return offlineText; } + set { offlineText = value; } + } + + private string bodyPayload = string.Empty; + + public string BodyPayload + { + get { return bodyPayload; } + set { bodyPayload = value; } + } + + + #endregion + + #region Public + + /// + /// Creates a xml message based on the data in the object. It is used before the message is send to the server. + /// + protected virtual XmlDocument CreateXmlMessage() + { + XmlDocument doc = new XmlDocument(); + XmlElement root = doc.CreateElement("NOTIFICATION"); + + if (NotificationTypeSpecified) + root.Attributes.Append(doc.CreateAttribute("ver")).Value = ((int)NotificationType).ToString(); + + root.Attributes.Append(doc.CreateAttribute("id")).Value = Id.ToString(); + if (siteId > 0) + root.Attributes.Append(doc.CreateAttribute("siteid")).Value = SiteId.ToString(); + if (siteUrl.Length > 0) + root.Attributes.Append(doc.CreateAttribute("siteurl")).Value = SiteUrl; + + XmlElement to = doc.CreateElement("TO"); + if (ReceiverMemberIdLow.Length > 0 && ReceiverMemberIdHigh.Length > 0) + to.Attributes.Append(doc.CreateAttribute("pid")).Value = ReceiverMemberIdLow.ToString() + ":" + ReceiverMemberIdHigh.ToString(); + if (ReceiverAccount.Length > 0) + to.Attributes.Append(doc.CreateAttribute("name")).Value = ReceiverAccount; + if (ReceiverOfflineMail.Length > 0) + to.Attributes.Append(doc.CreateAttribute("email")).Value = ReceiverOfflineMail; + if (SendDevice.Length > 0) + { + XmlElement via = doc.CreateElement("VIA"); + via.Attributes.Append(doc.CreateAttribute("agent")).Value = SendDevice; + to.AppendChild(via); + } + root.AppendChild(to); + + XmlElement from = doc.CreateElement("FROM"); + if (SenderMemberIdLow.Length > 0 && SenderMemberIdHigh.Length > 0) + from.Attributes.Append(doc.CreateAttribute("pid")).Value = SenderMemberIdLow.ToString() + ":" + SenderMemberIdHigh.ToString(); + if (SenderAccount.Length > 0) + from.Attributes.Append(doc.CreateAttribute("name")).Value = SenderAccount; + root.AppendChild(from); + + XmlElement msg = doc.CreateElement("MSG"); + if (Pri.Length > 0) + msg.Attributes.Append(doc.CreateAttribute("pri")).Value = Pri.ToString(); + + msg.Attributes.Append(doc.CreateAttribute("id")).Value = MessageId.ToString(); + + if (ActionUrl.Length > 0) + { + XmlElement action = doc.CreateElement("ACTION"); + action.Attributes.Append(doc.CreateAttribute("url")).Value = ActionUrl; + msg.AppendChild(action); + } + if (SubcriptionUrl.Length > 0) + { + XmlElement subscr = doc.CreateElement("SUBSCR"); + subscr.Attributes.Append(doc.CreateAttribute("url")).Value = SubcriptionUrl; + msg.AppendChild(subscr); + } + if (CatId.Length > 0) + { + XmlElement cat = doc.CreateElement("CAT"); + cat.Attributes.Append(doc.CreateAttribute("id")).Value = CatId.ToString(); + msg.AppendChild(cat); + } + + XmlElement body = doc.CreateElement("BODY"); + if (Language.Length > 0) + body.Attributes.Append(doc.CreateAttribute("id")).Value = Language; + if (IconUrl.Length > 0) + body.Attributes.Append(doc.CreateAttribute("icon")).Value = IconUrl; + if (Text.Length > 0) + { + XmlElement textEl = doc.CreateElement("TEXT"); + textEl.AppendChild(doc.CreateTextNode(Text)); + body.AppendChild(textEl); + } + + if (OfflineText.Length > 0) + { + XmlElement emailTextEl = doc.CreateElement("EMAILTEXT"); + emailTextEl.AppendChild(doc.CreateTextNode(OfflineText)); + body.AppendChild(emailTextEl); + } + msg.AppendChild(body); + + root.AppendChild(msg); + + doc.AppendChild(root); + + return doc; + + } + + /// + /// Returns the command message as a byte array. This can be directly send over a networkconnection. + /// + /// + /// Remember to set the transaction ID before calling this method. + /// Uses UTF8 Encoding. + /// + /// + public override byte[] GetBytes() + { + return new byte[] { 0x00 }; + //throw new MSNPSharpException("You can't send notification messages yourself. It is only possible to retrieve them."); + } + + /// + /// Parses incoming byte data send from the network. + /// + /// The raw message as received from the server + public override void ParseBytes(byte[] data) + { + if (data != null) + { + // retrieve the innerbody + XmlDocument xmlDoc = new XmlDocument(); + + TextReader reader = new StreamReader(new MemoryStream(data), new System.Text.UTF8Encoding(false)); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, reader.ReadToEnd(), GetType().Name); + + reader = new StreamReader(new MemoryStream(data), new System.Text.UTF8Encoding(false)); + xmlDoc.Load(reader); + + // Root node: NOTIFICATION + XmlNode node = xmlDoc.SelectSingleNode("//NOTIFICATION"); + if (node != null) + { + if (node.Attributes.GetNamedItem("ver") != null) + { + NotificationType = (NotificationType)int.Parse(node.Attributes.GetNamedItem("ver").Value); + NotificationTypeSpecified = true; + } + + if (node.Attributes.GetNamedItem("id") != null) + Id = int.Parse(node.Attributes.GetNamedItem("id").Value); + if (node.Attributes.GetNamedItem("siteid") != null) + SiteId = int.Parse(node.Attributes.GetNamedItem("siteid").Value); + if (node.Attributes.GetNamedItem("siteurl") != null) + SiteUrl = node.Attributes.GetNamedItem("siteurl").Value; + } + + // TO element + node = xmlDoc.SelectSingleNode("/NOTIFICATION/TO"); + if (node != null) + { + if (node.Attributes.GetNamedItem("pid") != null) + { + string[] values = node.Attributes.GetNamedItem("pid").Value.Split(':'); + ReceiverMemberIdLow = values[0]; + ReceiverMemberIdHigh = values[1]; + } + if (node.Attributes.GetNamedItem("name") != null) + ReceiverAccount = node.Attributes.GetNamedItem("name").Value; + if (node.Attributes.GetNamedItem("email") != null) + ReceiverOfflineMail = node.Attributes.GetNamedItem("email").Value; + } + + // VIA element + node = xmlDoc.SelectSingleNode("/NOTIFICATION/TO/VIA"); + if (node != null) + { + if (node.Attributes.GetNamedItem("agent") != null) + SendDevice = node.Attributes.GetNamedItem("agent").Value; + } + + // FROM element + node = xmlDoc.SelectSingleNode("/NOTIFICATION/FROM"); + if (node != null) + { + if (node.Attributes.GetNamedItem("pid") != null) + { + string[] values = node.Attributes.GetNamedItem("pid").Value.Split(':'); + SenderMemberIdLow = values[0]; + SenderMemberIdHigh = values[1]; + } + if (node.Attributes.GetNamedItem("name") != null) + SenderAccount = node.Attributes.GetNamedItem("name").Value; + } + + // MSG element + node = xmlDoc.SelectSingleNode("/NOTIFICATION/MSG"); + if (node != null) + { + if (node.Attributes.GetNamedItem("pri") != null) + Pri = node.Attributes.GetNamedItem("pri").Value; + if (node.Attributes.GetNamedItem("id") != null) + MessageId = int.Parse(node.Attributes.GetNamedItem("id").Value); + + } + + // ACTION element + node = xmlDoc.SelectSingleNode("/NOTIFICATION/MSG/ACTION"); + if (node != null) + { + if (node.Attributes.GetNamedItem("url") != null) + ActionUrl = node.Attributes.GetNamedItem("url").Value; + } + + // SUBSCR element + node = xmlDoc.SelectSingleNode("/NOTIFICATION/MSG/SUBSCR"); + if (node != null) + { + if (node.Attributes.GetNamedItem("url") != null) + SubcriptionUrl = node.Attributes.GetNamedItem("url").Value; + } + + // CAT element + node = xmlDoc.SelectSingleNode("/NOTIFICATION/MSG/CAT"); + if (node != null) + { + if (node.Attributes.GetNamedItem("id") != null) + CatId = node.Attributes.GetNamedItem("id").Value; + } + + // BODY element + node = xmlDoc.SelectSingleNode("/NOTIFICATION/MSG/BODY"); + if (node != null) + { + if (node.Attributes.GetNamedItem("lang") != null) + Language = node.Attributes.GetNamedItem("lang").Value; + if (node.Attributes.GetNamedItem("icon") != null) + IconUrl = node.Attributes.GetNamedItem("icon").Value; + } + + if (!NotificationTypeSpecified && Id == 0 && node != null) + { + bodyPayload = node.InnerText; + } + + // TEXT element + node = xmlDoc.SelectSingleNode("/NOTIFICATION/MSG/BODY/TEXT"); + if (node != null) + { + Text = node.Value; + } + + // EMAILTEXT element + node = xmlDoc.SelectSingleNode("/NOTIFICATION/MSG/BODY/EMAILTEXT"); + if (node != null) + { + OfflineText = node.Value; + } + + + } + else + throw new MSNPSharpException("NotificationMessage expected payload data, but not InnerBody is present."); + } + + + + + /// + /// + /// + public override string ToString() + { + return System.Text.UTF8Encoding.UTF8.GetString(this.GetBytes()); + } + + #endregion + } +}; diff --git a/MSNPSharp/Core/PersistentStream.cs b/MSNPSharp/Core/PersistentStream.cs new file mode 100644 index 0000000..af2f50d --- /dev/null +++ b/MSNPSharp/Core/PersistentStream.cs @@ -0,0 +1,244 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Security.Permissions; + +namespace MSNPSharp.Core +{ + using MSNPSharp; + + /// + /// A multi-user stream. + /// + public class PersistentStream : Stream + { + /// + /// + private Stream innerStream = null; + + #region Stream overrides + /// + /// + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + return innerStream.BeginRead(buffer, offset, count, callback, state); + } + /// + /// + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + return innerStream.BeginWrite(buffer, offset, count, callback, state); + } + /// + /// + public override bool CanRead + { + get + { + return innerStream.CanRead; + } + } + /// + /// + public override bool CanSeek + { + get + { + return innerStream.CanSeek; + } + } + /// + /// + public override bool CanWrite + { + get + { + return innerStream.CanWrite; + } + } + /// + /// + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)] + public override System.Runtime.Remoting.ObjRef CreateObjRef(Type requestedType) + { + return innerStream.CreateObjRef(requestedType); + } + + /// + /// + public override int EndRead(IAsyncResult asyncResult) + { + return innerStream.EndRead(asyncResult); + } + /// + /// + public override void EndWrite(IAsyncResult asyncResult) + { + innerStream.EndWrite(asyncResult); + } + /// + /// + public override bool Equals(object obj) + { + return innerStream.Equals(obj); + } + /// + /// + public override void Flush() + { + innerStream.Flush(); + } + /// + /// + public override int GetHashCode() + { + return innerStream.GetHashCode(); + } + /// + /// + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)] + public override object InitializeLifetimeService() + { + return innerStream.InitializeLifetimeService(); + } + /// + /// + public override long Length + { + get + { + return innerStream.Length; + } + } + /// + /// + public override long Position + { + get + { + return innerStream.Position; + } + set + { + innerStream.Position = value; + } + } + /// + /// + public override int Read(byte[] buffer, int offset, int count) + { + return innerStream.Read(buffer, offset, count); + } + /// + /// + public override int ReadByte() + { + return innerStream.ReadByte(); + } + /// + /// + public override long Seek(long offset, SeekOrigin origin) + { + return innerStream.Seek(offset, origin); + } + /// + /// + public override void SetLength(long value) + { + innerStream.SetLength(value); + } + /// + /// + public override string ToString() + { + return innerStream.ToString(); + } + + /// + /// + public override void Write(byte[] buffer, int offset, int count) + { + innerStream.Write(buffer, offset, count); + } + /// + /// + public override void WriteByte(byte value) + { + innerStream.WriteByte(value); + } + #endregion + + /// + /// Keeps track of the number of users using the stream. + /// + private int users; + + /// + /// The number of users using the stream. + /// + public int Users + { + get + { + return users; + } + } + + /// + /// Increases the number of users using this stream with 1. + /// + public void Open() + { + users++; + } + + /// + /// Decreases the number of users using this stream with 1. If the number of users is below 0 the stream will really be closed. + /// + public override void Close() + { + users--; + if (users <= 0) + innerStream.Close(); + } + + /// + /// + public PersistentStream(Stream stream) + { + innerStream = stream; + Open(); + } + } +}; diff --git a/MSNPSharp/Core/SBMessage.cs b/MSNPSharp/Core/SBMessage.cs new file mode 100644 index 0000000..8dcfb09 --- /dev/null +++ b/MSNPSharp/Core/SBMessage.cs @@ -0,0 +1,169 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Text; +using System.Collections; + +namespace MSNPSharp.Core +{ + using MSNPSharp; + using System.Globalization; + + [Serializable] + public class SBMessage : MSNMessage + { + private string acknowledgement = "N"; + protected bool hasAckField = false; + + public string Acknowledgement + { + get + { + return acknowledgement; + } + set + { + if (Command == "MSG") + hasAckField = true; + else + return; + + acknowledgement = value; + } + } + + public SBMessage() + { + } + + public SBMessage(string command, string[] commandValues) + : base(command, new ArrayList(commandValues)) + { + } + + public SBMessage(string command, ArrayList commandValues) + : base(command, commandValues) + { + } + + public override byte[] GetBytes() + { + StringBuilder builder = new StringBuilder(128); + builder.Append(Command); + + if (Command != "OUT") + { + if (TransactionID != -1) + { + builder.Append(' '); + builder.Append(TransactionID.ToString(CultureInfo.InvariantCulture)); + } + } + + if (Command == "MSG" && hasAckField) + { + builder.Append(' '); + builder.Append(Acknowledgement); + } + else + { + + foreach (string val in CommandValues) + { + builder.Append(' '); + builder.Append(val); + } + } + + if (InnerMessage != null && InnerBody == null) //This is a message created locally. + { + builder.Append(' '); + builder.Append(InnerMessage.GetBytes().Length.ToString(CultureInfo.InvariantCulture)); + } + + builder.Append("\r\n"); + + if (InnerMessage != null) + return AppendArray(System.Text.Encoding.UTF8.GetBytes(builder.ToString()), InnerMessage.GetBytes()); + else + return System.Text.Encoding.UTF8.GetBytes(builder.ToString()); + } + + public override string ToString() + { + StringBuilder builder = new StringBuilder(128); + builder.Append(Command); + + if (Command != "OUT") + { + if (TransactionID != -1) + { + builder.Append(' '); + builder.Append(TransactionID.ToString(CultureInfo.InvariantCulture)); + } + } + + if (Command == "MSG" && hasAckField) + { + builder.Append(' '); + builder.Append(Acknowledgement); + + foreach (string val in CommandValues) + { + builder.Append(' '); + builder.Append(val); + } + } + else + { + + foreach (string val in CommandValues) + { + builder.Append(' '); + builder.Append(val); + } + } + + if (InnerMessage != null && InnerBody == null) + { + builder.Append(' '); + builder.Append(InnerMessage.GetBytes().Length.ToString(CultureInfo.InvariantCulture)); + } + + builder.Append("\r\n"); + + return builder.ToString(); + } + } +}; diff --git a/MSNPSharp/Core/SBMessagePool.cs b/MSNPSharp/Core/SBMessagePool.cs new file mode 100644 index 0000000..dd999eb --- /dev/null +++ b/MSNPSharp/Core/SBMessagePool.cs @@ -0,0 +1,68 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Diagnostics; + +namespace MSNPSharp.Core +{ + using MSNPSharp; + + /// + /// Buffers and releases the messages for a switchboard + /// + public class SBMessagePool : NSMessagePool + { + public SBMessagePool() + { + } + + // Buffers data. + public override void BufferData(BinaryReader reader) + { + base.BufferData(reader); + + if (Settings.TraceSwitch.TraceVerbose) + { + if (MessageAvailable) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Message Available: ", GetType().Name); + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Buffering data...: ", GetType().Name); + } + } + } + } +}; diff --git a/MSNPSharp/Core/SocketMessageProcessor.cs b/MSNPSharp/Core/SocketMessageProcessor.cs new file mode 100644 index 0000000..6f246a7 --- /dev/null +++ b/MSNPSharp/Core/SocketMessageProcessor.cs @@ -0,0 +1,576 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Net; +using System.Threading; +using System.Net.Sockets; +using System.Collections; +using System.Diagnostics; +using System.Collections.Generic; +using Org.Mentalis.Network.ProxySocket; + +namespace MSNPSharp.Core +{ + using MSNPSharp; + + public abstract class SocketMessageProcessor : IMessageProcessor, IDisposable + { + private ConnectivitySettings connectivitySettings = new ConnectivitySettings(); + private byte[] socketBuffer = new byte[8192]; + private bool hasFiredDisconnectEvent = false; + private IPEndPoint proxyEndPoint = null; + private ProxySocket socket = null; + private MessagePool messagePool = null; + private List messageHandlers = new List(); + + public event EventHandler ConnectionEstablished; + public event EventHandler ConnectionClosed; + public event EventHandler ConnectingException; + public event EventHandler ConnectionException; + + public SocketMessageProcessor(ConnectivitySettings connectivitySettings) + { + ConnectivitySettings = connectivitySettings; + } + + ~SocketMessageProcessor() + { + Dispose(false); + } + + protected IPEndPoint ProxyEndPoint + { + get + { + return proxyEndPoint; + } + set + { + proxyEndPoint = value; + } + } + + protected MessagePool MessagePool + { + get + { + return messagePool; + } + set + { + messagePool = value; + } + } + + protected virtual ProxySocket GetPreparedSocket(IPAddress address, int port) + { + //Creates the Socket for sending data over TCP. + ProxySocket socket = new ProxySocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + + // incorporate the connection settings like proxy's + // Note: ProxyType is in MSNPSharp namespace, ProxyTypes in ProxySocket namespace. + if (ConnectivitySettings.ProxyType != ProxyType.None) + { + // set the proxy type + socket.ProxyType = (ConnectivitySettings.ProxyType == ProxyType.Socks4) + ? Org.Mentalis.Network.ProxySocket.ProxyTypes.Socks4 + : Org.Mentalis.Network.ProxySocket.ProxyTypes.Socks5; + + socket.ProxyUser = ConnectivitySettings.ProxyUsername; + socket.ProxyPass = ConnectivitySettings.ProxyPassword; + + // resolve the proxy host + if (proxyEndPoint == null) + { + bool worked = false; + int retries = 0; + Exception exp = null; + + //we retry a few times, because dns resolve failure is quite common + do + { + try + { + System.Net.IPHostEntry ipHostEntry = System.Net.Dns.GetHostEntry(ConnectivitySettings.ProxyHost); + System.Net.IPAddress ipAddress = ipHostEntry.AddressList[0]; + + // assign to the connection object so other sockets can make use of it quickly + proxyEndPoint = new IPEndPoint(ipAddress, ConnectivitySettings.ProxyPort); + + worked = true; + } + catch (Exception e) + { + retries++; + exp = e; + } + } while (!worked && retries < 3); + + if (!worked) + throw new ConnectivityException("DNS Resolve for the proxy server failed: " + ConnectivitySettings.ProxyHost + " failed.", exp); + } + + socket.ProxyEndPoint = proxyEndPoint; + } + else + socket.ProxyType = ProxyTypes.None; + + //Send operations will timeout of confirmation is not received within 3000 milliseconds. + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 3000); + + //Socket will linger for 2 seconds after close is called. + LingerOption lingerOption = new LingerOption(true, 2); + socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lingerOption); + + try + { + socket.Bind(new IPEndPoint(address, port)); + } + catch (SocketException ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "An error occured while trying to bind to a local address, error code: " + ex.ErrorCode + "."); + } + + return socket; + } + + protected virtual void EndSendCallback(IAsyncResult ar) + { + ProxySocket socket = (ProxySocket)ar.AsyncState; + socket.EndSend(ar); + } + + protected void SendSocketData(byte[] data) + { + if (socket == null || !Connected) + { + // the connection is closed + OnDisconnected(); + return; + } + + SendSocketData(socket, data); + } + + protected void SendSocketData(Socket psocket, byte[] data) + { + try + { + if (psocket != null && IsSocketConnected(psocket)) + { + lock (psocket) + { + psocket.Send(data); + } + } + else + { + OnDisconnected(); + } + } + catch (SocketException sex) + { + if (sex.NativeErrorCode != 10035) //10035: WSAEWOULDBLOCK + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "Error while sending network message. Error message: " + sex.Message); + OnDisconnected(); + } + + return; + } + catch (ObjectDisposedException) + { + // the connection is closed + OnDisconnected(); + } + catch (Exception e) + { + throw new MSNPSharpException("Error while sending network message. See the inner exception for more details.", e); + } + } + + protected virtual void EndReceiveCallback(IAsyncResult ar) + { + int cnt = 0; + try + { + System.Diagnostics.Debug.Assert(messagePool != null, "Field messagepool must be defined in derived class of SocketMessageProcessor."); + + Socket socket = (Socket)ar.AsyncState; + cnt = socket.EndReceive(ar); + if (cnt == 0) + { + // No data is received. We are disconnected. + OnDisconnected(); + return; + } + + // read the messages and dispatch to handlers + using (BinaryReader reader = new BinaryReader(new MemoryStream(socketBuffer, 0, cnt))) + { + messagePool.BufferData(reader); + } + while (messagePool.MessageAvailable) + { + // retrieve the message + byte[] incomingMessage = messagePool.GetNextMessageData(); + + + // call the virtual method to perform polymorphism, descendant classes can take care of it + OnMessageReceived(incomingMessage); + } + + // start a new read + BeginDataReceive(socket); + } + catch (SocketException e) + { + // close the socket upon a exception + if (socket != null && Connected) + socket.Close(); + + OnDisconnected(); + + // an exception Occurred, pass it through + if (ConnectionException != null) + ConnectionException(this, new ExceptionEventArgs(new ConnectivityException("SocketMessageProcessor encountered a socket exception while retrieving data. See the inner exception for more information.", e))); + } + catch (ObjectDisposedException) + { + // the connection is closed + OnDisconnected(); + } + catch (Exception e) + { + // close the socket upon a exception + if (socket != null && Connected) + socket.Close(); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, e.ToString() + "\r\n" + e.StackTrace + "\r\n", GetType().Name); + + OnDisconnected(); + + if (ConnectionException != null) + ConnectionException(this, new ExceptionEventArgs(new ConnectivityException("SocketMessageProcessor encountered a general exception while retrieving data. See the inner exception for more information.", e))); + } + } + + + protected virtual void EndConnectCallback(IAsyncResult ar) + { + try + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "End Connect Callback", GetType().Name); + + ((ProxySocket)socket).EndConnect(ar); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "End Connect Callback Daarna", GetType().Name); + + hasFiredDisconnectEvent = false; + OnConnected(); + + // Begin receiving data + BeginDataReceive(socket); + } + catch (Exception e) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "** EndConnectCallback exception **" + e.ToString(), GetType().Name); + + if (ConnectingException != null) + ConnectingException(this, new ExceptionEventArgs(new ConnectivityException("SocketMessageProcessor failed to connect to the specified endpoint. See the inner exception for more information.", e))); + } + } + + protected virtual void BeginDataReceive(Socket socket) + { + try + { + socketBuffer = new byte[socketBuffer.Length]; + socket.BeginReceive(socketBuffer, 0, socketBuffer.Length, SocketFlags.None, new AsyncCallback(EndReceiveCallback), socket); + } + catch (ObjectDisposedException) + { + OnDisconnected(); + } + } + + protected virtual void OnConnected() + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Connected", GetType().Name); + + if (ConnectionEstablished != null) + ConnectionEstablished(this, new EventArgs()); + } + + protected virtual void OnDisconnected() + { + if (hasFiredDisconnectEvent) + { + return; + } + else + { + hasFiredDisconnectEvent = true; + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Disconnected", GetType().Name); + + if (ConnectionClosed != null) + ConnectionClosed(this, new EventArgs()); + } + + public ConnectivitySettings ConnectivitySettings + { + get + { + return connectivitySettings; + } + + set + { + if (Connected) + { + string errorString = "Cannot set the ConnectivitySettings property of a connected " + GetType().ToString() + "."; + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, errorString); + throw new InvalidOperationException(errorString); + } + + connectivitySettings = value; + } + } + + public bool Connected + { + get + { + if (socket == null) + return false; + + lock (socket) + { + return IsSocketConnected(socket); + } + } + } + + /// + /// Show whether the socket is connected at a certain moment. + /// + /// + /// true if socket is connected, false if socket is disconnected. + public static bool IsSocketConnected(Socket socket) + { + bool returnValue = false; + + if (socket != null) + { + // Socket.Connected doesn't tell us if the socket is actually connected... + // http://msdn2.microsoft.com/en-us/library/system.net.sockets.socket.connected.aspx + + bool disposed = false; + bool blocking = socket.Blocking; + + try + { + socket.Blocking = false; + + int pollWait = 1; + + if (socket.Poll(pollWait, SelectMode.SelectRead) && socket.Available == 0) + { + returnValue = false; + } + else + { + returnValue = true; + } + + } + catch (SocketException ex) + { + // 10035 == WSAEWOULDBLOCK + if (ex.NativeErrorCode.Equals(10035)) + returnValue = true; + } + catch (ObjectDisposedException) + { + disposed = true; + returnValue = false; + } + finally + { + if (!disposed) + { + socket.Blocking = blocking; + } + } + } + + return returnValue; + } + + public EndPoint LocalEndPoint + { + get + { + return socket.LocalEndPoint; + } + } + + protected List MessageHandlers + { + get + { + return messageHandlers; + } + } + + public virtual void RegisterHandler(IMessageHandler handler) + { + if (handler != null && !messageHandlers.Contains(handler)) + { + lock (messageHandlers) + { + messageHandlers.Add(handler); + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, + handler.ToString() + " added to handler list.", GetType().Name); + } + } + } + + public virtual void UnregisterHandler(IMessageHandler handler) + { + if (handler != null) + { + lock (messageHandlers) + { + while (messageHandlers.Remove(handler)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, + handler.ToString() + " removed from handler list.", GetType().Name); + } + } + } + } + + /// + /// Connect to the target through ConnectivitySettins. + /// + /// Socket already connected. + public virtual void Connect() + { + if (socket != null && Connected) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "Connect() called, but already a socket available.", GetType().Name); + + // If you have to fail, fail noisily and as soon as possible. + throw new InvalidOperationException("Socket already connected."); + } + + try + { + // Create a socket + socket = GetPreparedSocket((ConnectivitySettings.LocalHost == string.Empty) ? IPAddress.Any : IPAddress.Parse(ConnectivitySettings.LocalHost), ConnectivitySettings.LocalPort); + + IPAddress hostIP = null; + + if (IPAddress.TryParse(ConnectivitySettings.Host, out hostIP)) + { + // start connecting + ((ProxySocket)socket).BeginConnect(new System.Net.IPEndPoint(IPAddress.Parse(ConnectivitySettings.Host), ConnectivitySettings.Port), new AsyncCallback(EndConnectCallback), socket); + } + else + { + ((ProxySocket)socket).BeginConnect(ConnectivitySettings.Host, ConnectivitySettings.Port, new AsyncCallback(EndConnectCallback), socket); + } + } + catch (Exception e) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Connecting exception: " + e.ToString(), GetType().Name); + + if (ConnectingException != null) + ConnectingException(this, new ExceptionEventArgs(e)); + + // re-throw the exception since the exception is thrown while in a blocking call + throw; //RethrowToPreserveStackDetails (without e) + } + } + + public virtual void Disconnect() + { + // clean up the socket properly + if (socket != null) + { + try + { + if (Connected) + { + socket.Shutdown(SocketShutdown.Both); + } + } + catch (Exception) + { + } + finally + { + socket.Close(); + } + + socket = null; + // We don't need to call OnDisconnect here since EndReceiveCallback will be call automatically later on. (This is not valid if disconnected remotelly) + // We need to call OnDisconnect after EndReceiveCallback if disconnected locally. + } + } + + public abstract void SendMessage(NetworkMessage message); + protected abstract void OnMessageReceived(byte[] data); + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + // Dispose managed resources + Disconnect(); + } + + // Free native resources + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } +}; diff --git a/MSNPSharp/Core/TextPayloadMessage.cs b/MSNPSharp/Core/TextPayloadMessage.cs new file mode 100644 index 0000000..43460aa --- /dev/null +++ b/MSNPSharp/Core/TextPayloadMessage.cs @@ -0,0 +1,111 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace MSNPSharp.Core +{ + public class TextPayloadMessage : NetworkMessage + { + private string text = string.Empty; + + /// + /// The payload text. + /// + public string Text + { + get + { + return text; + } + + private set + { + text = value; + InnerBody = Encoding.GetBytes(Text); + } + } + + private Encoding encoding = Encoding.UTF8; + + /// + /// The encoding used when parsing the payload text. + /// + public Encoding Encoding + { + get + { + return encoding; + } + + private set + { + encoding = value; + InnerBody = Encoding.GetBytes(Text); + } + } + + public TextPayloadMessage(string txt) + { + Text = txt; + + } + + public TextPayloadMessage(string txt, Encoding encode) + { + Text = txt; + Encoding = encode; + } + + public override byte[] GetBytes() + { + return Encoding.GetBytes(Text); + } + + public override void ParseBytes(byte[] data) + { + Text = Encoding.GetString(data); + } + + public override void PrepareMessage() + { + InnerBody = Encoding.GetBytes(Text); + } + + public override string ToString() + { + return Text.Replace("\r", "\\r").Replace("\n", "\\n\n"); + } + } +} diff --git a/MSNPSharp/Credentials.cs b/MSNPSharp/Credentials.cs new file mode 100644 index 0000000..c08dbfe --- /dev/null +++ b/MSNPSharp/Credentials.cs @@ -0,0 +1,229 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + /// + /// Specifies the user credentials. These settings are used when authentication + /// is required on the network. + /// + /// + /// The client identifier, together with the client code, represents + /// a unique way of identifying the client connected to the network. + /// + /// Third party softwarehouses can request their own identifier/code combination + /// for their software. These values have to be stored in the properties before connecting + /// to the network. + /// When you want to emulate the Microsoft MSN Messenger client, you can use any of the following + /// values: + /// + /// ClientID ClientCode Client Version Acknowledgement + /// msmsgs@msnmsgr.com Q1P7W2E4J9R8U3S5 + /// PROD0038W!61ZTF9 VT6PX?UQTM4WM%YR + /// PROD0058#7IL2{QD QHDCY@7R1TB6W?5B + /// PROD0061VRRZH@4F JXQ6J@TUOGYV@N0M + /// PROD0119GSJUC$18 ILTXC!4IXB5FB*PX + /// PROD0120PW!CCV9@ C1BX{V4W}Q3*10SM WLM 2009 v14.0.8050.1202 http://twitter.com/mynetx + /// + /// + /// Note that officially you must use an obtained license (client id and client code) from Microsoft in order to access the network legally! + /// After you have received your own license you can set the client id and client code in this class. + /// + [Serializable] + public class Credentials + { + private ClientInfo clientInfo = new ClientInfo(); + private string password; + private string account; + + public ClientInfo ClientInfo + { + get + { + return clientInfo; + } + } + + /// + /// Msn protocol + /// + public MsnProtocol MsnProtocol + { + get + { + return clientInfo.MsnProtocol; + } + } + + /// + /// The client identifier used to identify the clientsoftware. + /// + public string ClientID + { + get + { + return clientInfo.ProductID; + } + } + + /// + /// The client code used to identify the clientsoftware. + /// + public string ClientCode + { + get + { + return clientInfo.ProductKey; + } + } + + /// + /// Password for the account. Used when logging into the network. + /// + public string Password + { + get + { + return password; + } + set + { + password = value; + } + } + + /// + /// The account the identity uses. A typical messenger account is specified as name@hotmail.com. + /// + public string Account + { + get + { + return account; + } + set + { + account = value; + } + } + + /// + /// Constructor to instantiate a Credentials object. + /// + protected Credentials() + { + } + + public Credentials(MsnProtocol msnp) + : this(string.Empty, string.Empty) + { + } + + public Credentials(string account, string password) + : this(account, password, MsnProtocol.MSNP18) + { + } + + public Credentials(string account, string password, MsnProtocol msnp) + { + this.account = account; + this.password = password; + this.clientInfo = (ClientInfo)DefaultCredentials[msnp].Clone(); + } + + /// + /// Constructor to instantiate a Credentials object with the specified values. + /// + public Credentials(string account, string password, string clientID, string clientCode) + : this(account, password, clientID, clientCode, MsnProtocol.MSNP18) + { + } + + /// + /// Constructor to instantiate a Credentials object with the specified values and msn protocol speaking. + /// + public Credentials(string account, string password, string clientID, string clientCode, MsnProtocol msnp) + : this(account, password, msnp) + { + clientInfo.ProductID = clientID; + clientInfo.ProductKey = clientCode; + } + + static readonly Dictionary DefaultCredentials = new Dictionary(); + static Credentials() + { + // MSNP18 + ClientInfo msnp18 = new ClientInfo(); + msnp18.MsnProtocol = MsnProtocol.MSNP18; + msnp18.ProductID = "PROD0120PW!CCV9@"; + msnp18.ProductKey = "C1BX{V4W}Q3*10SM"; + msnp18.MessengerClientName = "MSNMSGR"; + msnp18.MessengerClientBuildVer = "14.0.8117.0416"; + msnp18.ApplicationId = "AAD9B99B-58E6-4F23-B975-D9EC1F9EC24A"; + msnp18.MessengerClientBrand = "msmsgs"; + DefaultCredentials[msnp18.MsnProtocol] = msnp18; + + } + } + + [Serializable] + public struct ClientInfo : ICloneable + { + public MsnProtocol MsnProtocol; + public string ApplicationId; + public string MessengerClientBuildVer; + public string MessengerClientName; + public string ProductID; + public string ProductKey; + public string MessengerClientBrand; + + public object Clone() + { + ClientInfo ci = new ClientInfo(); + ci.MsnProtocol = MsnProtocol; + ci.ApplicationId = String.Copy(ApplicationId); + ci.MessengerClientBuildVer = String.Copy(MessengerClientBuildVer); + ci.MessengerClientName = String.Copy(MessengerClientName); + ci.ProductID = String.Copy(ProductID); + ci.ProductKey = String.Copy(ProductKey); + ci.MessengerClientBrand = MessengerClientBrand; + + return ci; + } + + } +}; diff --git a/MSNPSharp/DataTransfer/MSNSLPHandler.cs b/MSNPSharp/DataTransfer/MSNSLPHandler.cs new file mode 100644 index 0000000..4085814 --- /dev/null +++ b/MSNPSharp/DataTransfer/MSNSLPHandler.cs @@ -0,0 +1,1937 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Net; +using System.Text; +using System.Timers; +using System.Drawing; +using System.Collections; +using System.Diagnostics; +using System.Net.Sockets; +using System.Globalization; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace MSNPSharp.DataTransfer +{ + using MSNPSharp; + using MSNPSharp.Core; + + public enum DCNonceType + { + None = 0, + Plain = 1, + Sha1 = 2 + } + + #region DataTransferType + + /// + /// Defines the type of datatransfer for a MSNSLPHandler + /// + public enum DataTransferType + { + /// + /// Unknown datatransfer type. + /// + Unknown, + /// + /// Filetransfer. + /// + File, + /// + /// Emoticon transfer. + /// + Emoticon, + /// + /// Displayimage transfer. + /// + DisplayImage, + /// + /// Activity invitation. + /// + Activity + } + + #endregion + + #region ActivityInfo + + /// + /// Holds the property of activity such as AppID and activity name. + /// + public class ActivityInfo + { + private uint appID = 0; + + /// + /// The AppID of activity. + /// + public uint AppID + { + get + { + return appID; + } + } + + private string activityName = string.Empty; + + /// + /// The name of activity. + /// + public string ActivityName + { + get + { + return activityName; + } + } + + protected ActivityInfo() + { + } + + public ActivityInfo(string contextString) + { + try + { + byte[] byts = Convert.FromBase64String(contextString); + string activityUrl = System.Text.Encoding.Unicode.GetString(byts); + string[] activityProperties = activityUrl.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + if (activityProperties.Length >= 3) + { + uint.TryParse(activityProperties[0], out appID); + activityName = activityProperties[2]; + } + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "An error occurs while parsing activity context, error info: " + + ex.Message); + } + } + + public override string ToString() + { + return "Activity info: " + appID.ToString() + " name: " + activityName; + } + + } + + #endregion + + #region P2PTransferSessionEventArgs + + /// + /// Used as event argument when a P2PTransferSession is affected. + /// + public class P2PTransferSessionEventArgs : EventArgs + { + /// + /// + private P2PTransferSession transferSession; + + /// + /// The affected transfer session + /// + public P2PTransferSession TransferSession + { + get + { + return transferSession; + } + set + { + transferSession = value; + } + } + + /// + /// Constructor. + /// + /// + public P2PTransferSessionEventArgs(P2PTransferSession transferSession) + { + this.transferSession = transferSession; + } + } + + #endregion + + /// + /// Handles invitations and requests for file transfers, emoticons, user displays and other msn objects. + /// + /// + /// MSNSLPHandler is responsible for communicating with the remote client about the transfer properties. + /// This means receiving and sending details about filelength, filename, user display context, etc. + /// When an invitation request is received the client programmer is asked to accept or decline the + /// invitation. This is done through the TransferInvitationReceived event. The client programmer must + /// handle this event and set the Accept and DataStream property in the event argument, see + /// . When the receiver of the invitation has accepted a + /// is created and used to actually send the data. In the case of user + /// displays or other msn objects the data transfer always goes over the switchboard. In case of a file + /// transfer there will be negotiating about the direct connection to setup. Depending on the + /// connectivity of both clients, a request for a direct connection is send to associated the + /// object. + /// + public class MSNSLPHandler : IMessageHandler, IDisposable + { + #region Events + + /// + /// Occurs when a transfer session is created. + /// + public event EventHandler TransferSessionCreated; + + /// + /// Occurs when a transfer session is closed. Either because the transfer has finished or aborted. + /// + public event EventHandler TransferSessionClosed; + + /// + /// Occurs when a remote client has send an invitation for a transfer session. + /// + public event EventHandler TransferInvitationReceived; + + #endregion + + #region Members + + private IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 0); + private IPEndPoint externalEndPoint = null; + private P2PVersion version = P2PVersion.P2PV1; + private int directConnectionExpireInterval = 6000; + private IMessageProcessor messageProcessor = null; + private Guid schedulerID = Guid.Empty; + + /// + /// A dictionary containing MSNSLPTransferProperties objects. Indexed by CallId; + /// + private Dictionary transferProperties = + new Dictionary(4); + + #endregion + + #region Constructors & Destructors + + protected MSNSLPHandler() + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Constructing object", GetType().Name); + } + + public MSNSLPHandler(P2PVersion ver, Guid invitationSchedulerId, IPAddress externalAddress) + { + version = ver; + schedulerID = invitationSchedulerId; + ExternalEndPoint = new IPEndPoint(externalAddress, 0); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, + String.Format("Constructing object, version = {0}\r\n" + + "A new {1} created, with scheduler id = {2}", + Version, GetType().Name, SchedulerID.ToString("B")), GetType().Name); + } + + /// + /// Destructor calls Dispose(false) + /// + ~MSNSLPHandler() + { + Dispose(false); + } + + /// + /// Closes all sessions. Dispose() calls Dispose(true) + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + // Free managed resources + CloseAllSessions(); + } + + // Free native resources if there are any. + } + + #endregion + + #region Properties + + /// + /// P2P version + /// + public P2PVersion Version + { + get + { + return version; + } + } + + /// + /// The message processor to send outgoing p2p messages to. + /// + public IMessageProcessor MessageProcessor + { + get + { + return messageProcessor; + } + set + { + if (value != null && object.ReferenceEquals(MessageProcessor, value)) + return; + + if (value == null && MessageProcessor != null) + { + MessageProcessor.UnregisterHandler(this); + messageProcessor = value; + return; + } + + if (MessageProcessor != null) + { + MessageProcessor.UnregisterHandler(this); + } + + messageProcessor = value; + messageProcessor.RegisterHandler(this); + } + } + + /// + /// The message session to send message to. This is simply the MessageProcessor property, + /// but explicitly casted as a P2PMessageSession. + /// + public P2PMessageSession MessageSession + { + get + { + return (P2PMessageSession)MessageProcessor; + } + } + + /// + /// The client's local end-point. This can differ from the external endpoint through the use of + /// routers. This value is used to determine how to set-up a direct connection. + /// + public IPEndPoint LocalEndPoint + { + get + { + IPAddress iphostentry = IPAddress.Any; + IPAddress[] addrList = Dns.GetHostEntry(System.Net.Dns.GetHostName()).AddressList; + + for (int IPC = 0; IPC < addrList.Length; IPC++) + { + if (addrList[IPC].AddressFamily == AddressFamily.InterNetwork) + { + localEndPoint.Address = addrList[IPC]; + break; + } + } + return localEndPoint; + } + } + + /// + /// The client end-point as perceived by the server. This can differ from the actual local endpoint + /// through the use of routers. This value is used to determine how to set-up a direct connection. + /// + public IPEndPoint ExternalEndPoint + { + get + { + return externalEndPoint; + } + + private set + { + externalEndPoint = value; + } + } + + /// + /// The P2P invitation scheduler guid. + /// + protected Guid SchedulerID + { + get + { + return schedulerID; + } + } + + #endregion + + #region SendInvitation + + #region MSNObject + + /// + /// Sends the remote contact a request for the given context. The invitation message is send over the current MessageProcessor. + /// + public P2PTransferSession SendInvitation(Contact localContact, Contact remoteContact, MSNObject msnObject) + { + // set class variables + MSNSLPTransferProperties properties = new MSNSLPTransferProperties(localContact, MessageSession.LocalContactEndPointID, + remoteContact, MessageSession.RemoteContactEndPointID); + properties.SessionId = (uint)(new Random().Next(50000, int.MaxValue)); + + + P2PMessage p2pMessage = new P2PMessage(Version); + P2PTransferSession transferSession = new P2PTransferSession(p2pMessage.Version, properties, MessageSession); + transferSession.TransferFinished += delegate + { + transferSession.SendDisconnectMessage(SLPRequestMessage.CreateClosingMessage(properties)); + }; + + Contact remote = MessageSession.RemoteContact; + string AppID = "1"; + + string msnObjectContext = msnObject.ContextPlain; + + if (msnObject.ObjectType == MSNObjectType.Emoticon) + { + properties.DataType = DataTransferType.Emoticon; + transferSession.MessageFooter = P2PConst.CustomEmoticonFooter11; + transferSession.DataStream = msnObject.OpenStream(); + AppID = transferSession.MessageFooter.ToString(); + + } + else if (msnObject.ObjectType == MSNObjectType.UserDisplay) + { + if (remoteContact.DisplayImage == remoteContact.UserTileLocation) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "The current display image of remote contact: " + remoteContact + "is the same with it's displayImage context, invitation will not be processed."); + return null; //If the display image is the same as current user tile string, do not process the invitation. + } + + properties.DataType = DataTransferType.DisplayImage; + transferSession.MessageFooter = P2PConst.DisplayImageFooter12; + + AppID = transferSession.MessageFooter.ToString(); + DisplayImage displayImage = msnObject as DisplayImage; + + if (displayImage == null) + throw new ArgumentNullException("msnObject is not a DisplayImage object."); + + msnObjectContext = remoteContact.UserTileLocation; + + + transferSession.TransferFinished += delegate(object sender, EventArgs ea) + { + //User display image is a special case, we use the default DataStream of a TransferSession. + //After the transfer finished, we create a new display image and fire the DisplayImageChanged event. + DisplayImage newDisplayImage = new DisplayImage(remoteContact.Mail.ToLowerInvariant(), transferSession.DataStream as MemoryStream); + remoteContact.SetDisplayImageAndFireDisplayImageChangedEvent(newDisplayImage); + }; + } + + if (string.IsNullOrEmpty(msnObjectContext)) + { + //This is a default displayImage or any object created by the client programmer. + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "[SendInvitation] msnObject does not have OriginalContext."); + throw new InvalidOperationException("Parameter msnObject does not have valid OriginalContext property."); + } + + byte[] contextArray = System.Text.Encoding.UTF8.GetBytes(msnObjectContext); + + string base64Context = Convert.ToBase64String(contextArray, 0, contextArray.Length); + properties.Context = base64Context; + + properties.LastBranch = Guid.NewGuid().ToString("B").ToUpper(CultureInfo.InvariantCulture); + properties.CallId = Guid.NewGuid(); + + SLPRequestMessage slpMessage = new SLPRequestMessage(properties.RemoteContactEPIDString, MSNSLPRequestMethod.INVITE); + slpMessage.ToMail = properties.RemoteContactEPIDString; + slpMessage.FromMail = properties.LocalContactEPIDString; + slpMessage.Branch = properties.LastBranch; + slpMessage.CSeq = 0; + slpMessage.CallId = properties.CallId; + slpMessage.MaxForwards = 0; + slpMessage.ContentType = "application/x-msnmsgr-sessionreqbody"; + + slpMessage.BodyValues["EUF-GUID"] = P2PConst.UserDisplayGuid; + slpMessage.BodyValues["SessionID"] = properties.SessionId.ToString(); + + if (version == P2PVersion.P2PV1) + { + slpMessage.BodyValues["SChannelState"] = "0"; + slpMessage.BodyValues["Capabilities-Flags"] = "1"; + + p2pMessage.V1Header.Flags = P2PFlag.MSNSLPInfo; + transferSession.MessageFlag = (uint)P2PFlag.MSNObjectData; + } + + if (version == P2PVersion.P2PV2) + { + slpMessage.BodyValues["RequestFlags"] = "18"; + } + + slpMessage.BodyValues["AppID"] = AppID; + slpMessage.BodyValues["Context"] = base64Context; + + p2pMessage.InnerMessage = slpMessage; + + if (p2pMessage.Version == P2PVersion.P2PV2) + { + p2pMessage.V2Header.OperationCode = (byte)(OperationCode.SYN | OperationCode.RAK); + p2pMessage.V2Header.AppendPeerInfoTLV(); + + if (p2pMessage.V2Header.MessageSize - p2pMessage.V2Header.DataPacketHeaderLength > 1202) + { + p2pMessage.V2Header.PackageNumber = (ushort)((p2pMessage.V2Header.MessageSize - p2pMessage.V2Header.DataPacketHeaderLength) / 1202 + 1); + } + else + { + p2pMessage.V2Header.PackageNumber = 0; + } + transferSession.DataPacketNumber = p2pMessage.V2Header.PackageNumber; + + p2pMessage.V2Header.TFCombination = TFCombination.First; + + } + + // store the transferproperties + lock (transferProperties) + transferProperties[properties.CallId] = properties; + + + transferSession.IsSender = false; + + OnTransferSessionCreated(transferSession); + + // send the invitation + Schedulers.P2PInvitationScheduler.Enqueue(transferSession, p2pMessage, SchedulerID); + + return transferSession; + } + + #endregion + + #region Activity + + /// + /// Sends the remote contact a invitation for the activity. The invitation message is send over the current MessageProcessor. + /// + /// + /// + /// The ID of activity, that was register by Microsoft. + /// The name of Activity. + /// + /// + /// + /// //An example that invites a remote user to attend the "Music Mix" activity. + /// + /// String remoteAccount = @"remoteUser@hotmail.com"; + /// + /// String activityID = "20521364"; //The activityID of Music Mix activity. + /// String activityName = "Music Mix"; //The name of acticvity + /// + /// P2PMessageSession session = Conversation.Messenger.P2PHandler.GetSession(Conversation.Messenger.ContactList.Owner.Mail, remoteAccount); + /// MSNSLPHandler slpHandler = session.GetHandler(typeof(MSNSLPHandler)) as MSNSLPHandler ; + /// slpHandler.SendInvitation(Conversation.Messenger.ContactList.Owner.Mail, remoteaccount, activityID, activityName); + /// + /// + public P2PTransferSession SendInvitation(Contact localContact, Contact remoteContact, string applicationID, string activityName) + { + // set class variables + return SendInvitation(localContact, remoteContact, applicationID, activityName, string.Empty, 0); + } + + /// + /// Sends the remote contact a invitation for the activity. The invitation message is send over the current MessageProcessor. + /// + /// + /// + /// The ID of activity, that was register by Microsoft. + /// The name of Activity. + /// The parameter string that want to send to the activity window. + /// + /// + /// + /// //An example that invites a remote user to attend the "Music Mix" activity. + /// + /// String remoteAccount = @"remoteUser@hotmail.com"; + /// + /// String activityID = "20521364"; //The activityID of Music Mix activity. + /// String activityName = "Music Mix"; //The name of acticvity + /// String userName = "Pang Wu"; //The parameter send to the client's activity window. + /// + /// P2PMessageSession session = Conversation.Messenger.P2PHandler.GetSession(Conversation.Messenger.ContactList.Owner.Mail, remoteAccount); + /// MSNSLPHandler slpHandler = session.GetHandler(typeof(MSNSLPHandler)) as MSNSLPHandler ; + /// slpHandler.SendInvitation(Conversation.Messenger.ContactList.Owner.Mail, remoteaccount, activityID, activityName, activityData); + /// + /// + public P2PTransferSession SendInvitation(Contact localContact, Contact remoteContact, string applicationID, string activityName, string activityData) + { + return SendInvitation(localContact, remoteContact, applicationID, activityName, activityData, 6000); + } + + /// + /// Sends the remote contact a invitation for the activity. The invitation message is send over the current MessageProcessor. + /// + /// + /// + /// The ID of activity, that was register by Microsoft. + /// The name of Activity. + /// The parameter string that want to send to the activity window. + /// How long should the library wait (in ms.) to send out the activityData after the use accepted the invitation. + /// + /// + /// + /// //An example that invites a remote user to attend the "Music Mix" activity. + /// + /// String remoteAccount = @"remoteUser@hotmail.com"; + /// + /// String activityID = "20521364"; //The activityID of Music Mix activity. + /// String activityName = "Music Mix"; //The name of acticvity + /// String activityData = "Pang Wu"; //The parameter send to the client's activity window. + /// + /// P2PMessageSession session = Conversation.Messenger.P2PHandler.GetSession(Conversation.Messenger.ContactList.Owner.Mail, remoteAccount); + /// MSNSLPHandler slpHandler = session.GetHandler(typeof(MSNSLPHandler)) as MSNSLPHandler ; + /// slpHandler.SendInvitation(Conversation.Messenger.ContactList.Owner.Mail, remoteaccount, activityID, activityName, activityData, 5000); + /// + /// + public P2PTransferSession SendInvitation(Contact localContact, Contact remoteContact, string applicationID, string activityName, string activityData, int directConnectionExpireInterval) + { + this.directConnectionExpireInterval = directConnectionExpireInterval; + + // set class variables + MSNSLPTransferProperties properties = new MSNSLPTransferProperties(localContact, MessageSession.LocalContactEndPointID, + remoteContact, MessageSession.RemoteContactEndPointID); + properties.SessionId = (uint)(new Random().Next(50000, int.MaxValue)); + + properties.DataType = DataTransferType.Activity; + + string activityID = applicationID + ";1;" + activityName; + byte[] contextData = System.Text.UnicodeEncoding.Unicode.GetBytes(activityID); + string base64Context = Convert.ToBase64String(contextData, 0, contextData.Length); + + properties.Context = base64Context; + + properties.LastBranch = Guid.NewGuid().ToString("B").ToUpper(CultureInfo.InvariantCulture); + properties.CallId = Guid.NewGuid(); + + SLPRequestMessage slpMessage = new SLPRequestMessage(properties.RemoteContactEPIDString, MSNSLPRequestMethod.INVITE); + slpMessage.ToMail = properties.RemoteContactEPIDString; + slpMessage.FromMail = properties.LocalContactEPIDString; + slpMessage.Branch = properties.LastBranch; + slpMessage.CSeq = 0; + slpMessage.CallId = properties.CallId; + slpMessage.MaxForwards = 0; + slpMessage.ContentType = "application/x-msnmsgr-sessionreqbody"; + slpMessage.BodyValues["EUF-GUID"] = P2PConst.ActivityGuid; + slpMessage.BodyValues["SessionID"] = properties.SessionId.ToString(); + slpMessage.BodyValues["SChannelState"] = "0"; + slpMessage.BodyValues["Capabilities-Flags"] = "1"; + slpMessage.BodyValues["AppID"] = applicationID.ToString(); + slpMessage.BodyValues["Context"] = base64Context; + + if (Version == P2PVersion.P2PV2) + { + slpMessage.BodyValues["RequestFlags"] = "16"; + } + + P2PMessage p2pMessage = new P2PMessage(Version); + p2pMessage.InnerMessage = slpMessage; + + lock (transferProperties) + transferProperties[properties.CallId] = properties; + + // create a transfer session to handle the actual data transfer + P2PTransferSession transferSession = new P2PTransferSession(Version, properties, MessageSession); + + if (Version == P2PVersion.P2PV2) + { + p2pMessage.V2Header.OperationCode = (byte)(OperationCode.SYN | OperationCode.RAK); + p2pMessage.V2Header.AppendPeerInfoTLV(); + + if (p2pMessage.V2Header.MessageSize - p2pMessage.V2Header.DataPacketHeaderLength > 1202) + { + p2pMessage.V2Header.PackageNumber = (ushort)((p2pMessage.V2Header.MessageSize - p2pMessage.V2Header.DataPacketHeaderLength) / 1202 + 1); + } + else + { + p2pMessage.V2Header.PackageNumber = 0; + } + transferSession.DataPacketNumber = p2pMessage.V2Header.PackageNumber; + + p2pMessage.V2Header.TFCombination = TFCombination.First; + } + + if (activityData != string.Empty && activityData != null) + { + activityData += "\0"; + + int urlLength = Encoding.Unicode.GetByteCount(activityData); + + MemoryStream urlDataStream = new MemoryStream(); + + byte[] header = null; + ; + + if (Version == P2PVersion.P2PV1) + { + header = new byte[] { 0x80, 0x00, 0x00, 0x00 }; + } + + if (Version == P2PVersion.P2PV2) + { + header = new byte[] { 0x80, 0x3f, 0x14, 0x05 }; + } + + urlDataStream.Write(header, 0, header.Length); + urlDataStream.Write(BitUtility.GetBytes((ushort)0x08, true), 0, sizeof(ushort)); //data type: 0x08: string + urlDataStream.Write(BitUtility.GetBytes(urlLength, true), 0, sizeof(int)); + urlDataStream.Write(Encoding.Unicode.GetBytes(activityData), 0, urlLength); + + urlDataStream.Seek(0, SeekOrigin.Begin); + transferSession.DataStream = urlDataStream; + transferSession.IsSender = true; + } + + transferSession.MessageFlag = (uint)P2PFlag.Normal; + transferSession.TransferFinished += delegate + { + transferSession.SendDisconnectMessage(SLPRequestMessage.CreateClosingMessage(properties)); + }; + + + OnTransferSessionCreated(transferSession); + Schedulers.P2PInvitationScheduler.Enqueue(transferSession, p2pMessage, SchedulerID); + + return transferSession; + } + + #endregion + + #region File + + /// + /// Sends the remote contact a request for the filetransfer. The invitation message is send over the current MessageProcessor. + /// + /// + /// + /// + /// + public P2PTransferSession SendInvitation(Contact localContact, Contact remoteContact, string filename, Stream file) + { + + MSNSLPTransferProperties properties = new MSNSLPTransferProperties( + localContact, MessageSession.LocalContactEndPointID, remoteContact, MessageSession.RemoteContactEndPointID); + + do + { + properties.SessionId = (uint)(new Random().Next(50000, int.MaxValue)); + } + while (MessageSession.GetTransferSession(properties.SessionId) != null); + + properties.LastBranch = Guid.NewGuid().ToString("B").ToUpper(CultureInfo.InvariantCulture); + properties.CallId = Guid.NewGuid(); + + properties.DataType = DataTransferType.File; + + //0-7: location of the FT preview + //8-15: file size + //16-19: I don't know or need it so... + //20-540: location I use to get the file name + // set class variables + // size: location (8) + file size (8) + unknown (4) + filename (236) = 256 + + // create a new bytearray to build up the context + byte[] contextArray = new byte[574];// + picturePreview.Length]; + BinaryWriter binWriter = new BinaryWriter(new MemoryStream(contextArray, 0, contextArray.Length, true)); + + // length of preview data + binWriter.Write((int)574); + + // don't know some sort of flag + binWriter.Write((int)2); + + // send the total size of the file we are to transfer + + binWriter.Write((long)file.Length); + + // don't know some sort of flag + binWriter.Write((int)1); + + // write the filename in the context + binWriter.Write(System.Text.UnicodeEncoding.Unicode.GetBytes(filename)); + + // convert to base 64 string + //base64Context = "PgIAAAIAAAAVAAAAAAAAAAEAAABkAGMALgB0AHgAdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + string base64Context = Convert.ToBase64String(contextArray, 0, contextArray.Length); + + // set our current context + properties.Context = base64Context; + + // store the transferproperties + lock (transferProperties) + transferProperties[properties.CallId] = properties; + + // create the message + SLPRequestMessage slpMessage = new SLPRequestMessage(properties.RemoteContactEPIDString, MSNSLPRequestMethod.INVITE); + slpMessage.ToMail = properties.RemoteContactEPIDString; + slpMessage.FromMail = properties.LocalContactEPIDString; + slpMessage.Branch = properties.LastBranch; + slpMessage.CSeq = 0; + slpMessage.CallId = properties.CallId; + slpMessage.MaxForwards = 0; + slpMessage.ContentType = "application/x-msnmsgr-sessionreqbody"; + slpMessage.BodyValues["EUF-GUID"] = P2PConst.FileTransferGuid; + slpMessage.BodyValues["SessionID"] = properties.SessionId.ToString(); + slpMessage.BodyValues["AppID"] = P2PConst.FileTransFooter2.ToString(); + slpMessage.BodyValues["Context"] = base64Context; + + if (Version == P2PVersion.P2PV2) + { + slpMessage.BodyValues["RequestFlags"] = "16"; + } + + P2PMessage p2pMessage = new P2PMessage(Version); + p2pMessage.InnerMessage = slpMessage; + + // create a transfer session to handle the actual data transfer + P2PTransferSession transferSession = new P2PTransferSession(Version, properties, MessageSession); + + if (Version == P2PVersion.P2PV2) + { + p2pMessage.V2Header.OperationCode = (byte)(OperationCode.RAK | OperationCode.SYN); + p2pMessage.V2Header.AppendPeerInfoTLV(); + + if (p2pMessage.V2Header.MessageSize - p2pMessage.V2Header.DataPacketHeaderLength > 1202) + { + p2pMessage.V2Header.PackageNumber = (ushort)((p2pMessage.V2Header.MessageSize - p2pMessage.V2Header.DataPacketHeaderLength) / 1202 + 1); + } + else + { + p2pMessage.V2Header.PackageNumber = 0; + } + transferSession.DataPacketNumber = p2pMessage.V2Header.PackageNumber; + + p2pMessage.V2Header.TFCombination = TFCombination.First; + } + + transferSession.MessageFlag = (uint)P2PFlag.FileData; + transferSession.MessageFooter = P2PConst.FileTransFooter2; + + transferSession.TransferFinished += delegate + { + transferSession.SendDisconnectMessage(SLPRequestMessage.CreateClosingMessage(properties)); + }; + + // set the data stream to read from + transferSession.DataStream = file; + transferSession.IsSender = true; + + OnTransferSessionCreated(transferSession); + + Schedulers.P2PInvitationScheduler.Enqueue(transferSession, p2pMessage, SchedulerID); + + return transferSession; + } + + #endregion + + #endregion + + #region Accept/Reject Transfer + + /// + /// The client programmer should call this if he wants to reject the transfer + /// + public void RejectTransfer(MSNSLPInvitationEventArgs invitationArgs) + { + if (invitationArgs.TransferSession != null) + { + invitationArgs.TransferSession.SendMessage(SLPStatusMessage.CreateDeclineMessage(invitationArgs.TransferProperties)); + invitationArgs.TransferSession.SendMessage(SLPRequestMessage.CreateClosingMessage(invitationArgs.TransferProperties)); + + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[RejectTransfer Error] No transfer session attached."); + } + } + + /// + /// The client programmer should call this if he wants to accept the transfer + /// + public void AcceptTransfer(MSNSLPInvitationEventArgs invitationArgs) + { + MSNSLPTransferProperties properties = invitationArgs.TransferProperties; + P2PTransferSession transferSession = invitationArgs.TransferSession; + SLPMessage message = invitationArgs.InvitationMessage; + + // check for a valid datastream + if (invitationArgs.TransferSession.DataStream == null) + throw new MSNPSharpException("The invitation was accepted, but no datastream to read to/write from has been specified."); + + // the client programmer has accepted, continue ! + lock (transferProperties) + transferProperties[properties.CallId] = properties; + + // we want to be notified of messages through this session + transferSession.RegisterHandler(this); + transferSession.DataStream = invitationArgs.TransferSession.DataStream; + + + switch (message.BodyValues["EUF-GUID"].ToString().ToUpper(System.Globalization.CultureInfo.InvariantCulture)) + { + case P2PConst.UserDisplayGuid: + { + // for some kind of weird behavior, our local identifier must now subtract 4 ? + transferSession.IsSender = true; + transferSession.MessageFlag = (uint)P2PFlag.MSNObjectData; + transferSession.MessageFooter = P2PConst.DisplayImageFooter12; + + break; + } + + case P2PConst.FileTransferGuid: + { + transferSession.IsSender = false; + transferSession.MessageFlag = (uint)P2PFlag.FileData; + transferSession.MessageFooter = P2PConst.FileTransFooter2; + break; + } + + case P2PConst.ActivityGuid: + { + transferSession.MessageFlag = (uint)P2PFlag.Normal; + if (message.BodyValues.ContainsKey("AppID")) + { + uint appID = 0; + uint.TryParse(message.BodyValues["AppID"].Value, out appID); + transferSession.MessageFooter = appID; + } + transferSession.IsSender = false; + break; + } + } + + OnTransferSessionCreated(transferSession); + transferSession.AcceptInvitation(SLPStatusMessage.CreateAcceptanceMessage(properties)); + } + + #endregion + + #region CloseSession & CloseAllSessions + + /// + /// Close the specified session + /// + /// Session to close + public void CloseSession(P2PTransferSession transferSession) + { + if (transferSession != null) + { + transferSession.SendMessage(SLPRequestMessage.CreateClosingMessage(transferSession.TransferProperties)); + System.Threading.Thread.Sleep(300); + transferSession.AbortTransfer(); + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[CloseSessions Error] No transfer session attached on transfer layer."); + } + } + + /// + /// Closes all sessions by sending the remote client a closing message for each session available. + /// + public void CloseAllSessions() + { + foreach (MSNSLPTransferProperties properties in transferProperties.Values) + { + P2PMessageSession session = (P2PMessageSession)MessageProcessor; + P2PTransferSession transferSession = session.GetTransferSession(properties.SessionId); + if (transferSession != null) + { + CloseSession(transferSession); + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[CloseAllSessions Error] No transfer session attached on transfer layer."); + } + } + } + + #endregion + + #region Event Handlers + + /// + /// Fires the TransferInvitationReceived event. + /// + /// + protected virtual void OnTransferInvitationReceived(MSNSLPInvitationEventArgs e) + { + if (TransferInvitationReceived != null) + TransferInvitationReceived(this, e); + } + + /// + /// Fires the TransferSessionClosed event. + /// + protected virtual void OnTransferSessionClosed(P2PTransferSession session) + { + if (TransferSessionClosed != null) + TransferSessionClosed(this, new P2PTransferSessionEventArgs(session)); + } + + /// + /// Fires the TransferSessionCreated event and registers event handlers. + /// + protected virtual void OnTransferSessionCreated(P2PTransferSession session) + { + session.TransferFinished += new EventHandler(MSNSLPHandler_TransferFinished); + session.TransferAborted += new EventHandler(MSNSLPHandler_TransferAborted); + + if (TransferSessionCreated != null) + TransferSessionCreated(this, new P2PTransferSessionEventArgs(session)); + } + + /// + /// Cleans up the transfer session. + /// + /// + /// + private void MSNSLPHandler_TransferAborted(object sender, EventArgs e) + { + P2PTransferSession session = (P2PTransferSession)sender; + RemoveTransferSession(session); + } + + /// + /// Closes the datastream and sends the closing message, if the local client is the receiver. + /// Afterwards the associated object is removed from the class's + /// object. + /// + private void MSNSLPHandler_TransferFinished(object sender, EventArgs e) + { + P2PTransferSession transferSession = (P2PTransferSession)sender; + Contact remote = MessageSession.RemoteContact; + MSNSLPTransferProperties properties = transferSession.TransferProperties; + + if (properties.RemoteInvited == false) + { + if (Version == P2PVersion.P2PV1) + { + // we are the receiver. send close message back + P2PMessage p2pMessage = new P2PMessage(transferSession.Version); + p2pMessage.InnerMessage = SLPRequestMessage.CreateClosingMessage(properties); + p2pMessage.V1Header.Flags = P2PFlag.MSNSLPInfo; + MessageProcessor.SendMessage(p2pMessage); + } + + // close it + RemoveTransferSession(transferSession); + } + } + + #endregion + + #region Helpers + + /// + /// Returns the MSNSLPTransferProperties object associated with the specified call id. + /// + /// + /// + protected MSNSLPTransferProperties GetTransferProperties(Guid callId) + { + return transferProperties.ContainsKey(callId) ? transferProperties[callId] : null; + } + + /// + /// Closes the session's datastream and removes the transfer sessions from the class' object (MessageProcessor property). + /// + /// + protected virtual void RemoveTransferSession(P2PTransferSession session) + { + // remove the session + OnTransferSessionClosed(session); + + if (session.AutoCloseStream) + session.DataStream.Close(); + + MessageSession.RemoveTransferSession(session); + } + + /// + /// Extracts the checksum (SHA1C/SHA1D field) from the supplied context. + /// + /// The context must be a plain string, no base-64 decoding will be done + /// + /// + private static string ExtractChecksum(string context) + { + Regex shaRe = new Regex("SHA1C=\"([^\"]+)\""); + Match match = shaRe.Match(context); + if (match.Success) + { + return match.Groups[1].Value; + } + else + { + shaRe = new Regex("SHA1D=\"([^\"]+)\""); + match = shaRe.Match(context); + if (match.Success) + return match.Groups[1].Value; + } + throw new MSNPSharpException("SHA field could not be extracted from the specified context: " + context); + } + + internal static Guid ParseDCNonce(MimeDictionary bodyValues, out DCNonceType dcNonceType) + { + dcNonceType = DCNonceType.None; + Guid nonce = Guid.Empty; + + if (bodyValues.ContainsKey("Hashed-Nonce")) + { + nonce = new Guid(bodyValues["Hashed-Nonce"].Value); + dcNonceType = DCNonceType.Sha1; + } + else if (bodyValues.ContainsKey("Nonce")) + { + nonce = new Guid(bodyValues["Nonce"].Value); + dcNonceType = DCNonceType.Plain; + } + + return nonce; + } + + /// + /// Parses the incoming invitation message. This will set the class's properties for later retrieval in following messages. + /// + /// + protected virtual MSNSLPTransferProperties ParseInvitationMessage(SLPMessage message) + { + MSNSLPTransferProperties properties = new MSNSLPTransferProperties(MessageSession.LocalContact, message.ToEndPoint, MessageSession.RemoteContact, message.FromEndPoint); + + properties.RemoteInvited = true; + + if (message.BodyValues.ContainsKey("EUF-GUID")) + { + properties.DataTypeGuid = message.BodyValues["EUF-GUID"].ToString(); + if (message.BodyValues["EUF-GUID"].ToString().ToUpper(System.Globalization.CultureInfo.InvariantCulture) == P2PConst.UserDisplayGuid) + { + // create a temporary msn object to extract the data type + if (message.BodyValues.ContainsKey("Context")) + { + MSNObject msnObject = new MSNObject(); + msnObject.SetContext(message.BodyValues["Context"].ToString(), true); + + if (msnObject.ObjectType == MSNObjectType.UserDisplay) + properties.DataType = DataTransferType.DisplayImage; + else if (msnObject.ObjectType == MSNObjectType.Emoticon) + properties.DataType = DataTransferType.Emoticon; + else + properties.DataType = DataTransferType.Unknown; + + properties.Context = System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(message.BodyValues["Context"].ToString())); + properties.Checksum = ExtractChecksum(properties.Context); + } + else + { + properties.DataType = DataTransferType.Unknown; + } + } + else if (message.BodyValues["EUF-GUID"].ToString().ToUpper(System.Globalization.CultureInfo.InvariantCulture) == P2PConst.FileTransferGuid) + { + properties.DataType = DataTransferType.File; + } + else if (message.BodyValues["EUF-GUID"].ToString().ToUpper(System.Globalization.CultureInfo.InvariantCulture) == P2PConst.ActivityGuid) + { + properties.DataType = DataTransferType.Activity; + } + else + { + properties.DataType = DataTransferType.Unknown; + } + + // store the branch for use in the OK Message + properties.LastBranch = message.Branch; + properties.LastCSeq = message.CSeq; + properties.CallId = message.CallId; + properties.SessionId = uint.Parse(message.BodyValues["SessionID"].ToString(), System.Globalization.CultureInfo.InvariantCulture); + } + + return properties; + } + + /// + /// Sends the invitation request for a direct connection + /// + protected virtual void SendDCInvitation(MSNSLPTransferProperties transferProperties) + { + // Create a new branch, but keep the same callid as the first invitation + transferProperties.LastBranch = Guid.NewGuid().ToString("B").ToUpper(CultureInfo.InvariantCulture); + + transferProperties.DCNonceType = DCNonceType.Plain; // We prefer this :) + transferProperties.Nonce = Guid.NewGuid(); + transferProperties.HashedNonce = HashedNonceGenerator.HashNonce(transferProperties.Nonce); + + string connectionType = "Unknown-Connect"; + string netId = "2042264281"; // unknown variable + + #region Check and determine connectivity + + if (LocalEndPoint == null || this.ExternalEndPoint == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "LocalEndPoint or ExternalEndPoint are not set. Connection type will be set to unknown.", GetType().Name); + } + else + { + if (LocalEndPoint.Address.Equals(ExternalEndPoint.Address)) + { + if (LocalEndPoint.Port == ExternalEndPoint.Port) + connectionType = "Direct-Connect"; + else + connectionType = "Port-Restrict-NAT"; + } + else + { + if (LocalEndPoint.Port == ExternalEndPoint.Port) + { + netId = "0"; + connectionType = "IP-Restrict-NAT"; + } + else + connectionType = "Symmetric-NAT"; + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Connection type set to " + connectionType + " for session " + transferProperties.SessionId.ToString(CultureInfo.InvariantCulture), GetType().Name); + } + + #endregion + + // Create the message + SLPRequestMessage slpMessage = new SLPRequestMessage(transferProperties.RemoteContactEPIDString, MSNSLPRequestMethod.INVITE); + slpMessage.ToMail = transferProperties.RemoteContactEPIDString; + slpMessage.FromMail = transferProperties.LocalContactEPIDString; + slpMessage.Branch = transferProperties.LastBranch; + slpMessage.CSeq = 0; + slpMessage.CallId = transferProperties.CallId; + slpMessage.MaxForwards = 0; + slpMessage.ContentType = "application/x-msnmsgr-transreqbody"; + + slpMessage.BodyValues["Bridges"] = "TCPv1 SBBridge"; + slpMessage.BodyValues["Capabilities-Flags"] = "1"; + slpMessage.BodyValues["NetID"] = netId; + slpMessage.BodyValues["Conn-Type"] = connectionType; + slpMessage.BodyValues["TCP-Conn-Type"] = connectionType; + slpMessage.BodyValues["UPnPNat"] = "false"; // UPNP Enabled + slpMessage.BodyValues["ICF"] = "false"; // Firewall enabled + if (transferProperties.DCNonceType == DCNonceType.Sha1) + { + slpMessage.BodyValues["Hashed-Nonce"] = transferProperties.HashedNonce.ToString("B").ToUpper(System.Globalization.CultureInfo.InvariantCulture); + } + + P2PMessage p2pMessage = new P2PMessage(Version); + p2pMessage.InnerMessage = slpMessage; + + if (Version == P2PVersion.P2PV2) + { + p2pMessage.V2Header.TFCombination = TFCombination.First; + + if (p2pMessage.V2Header.MessageSize - p2pMessage.V2Header.DataPacketHeaderLength > 1202) + { + p2pMessage.V2Header.PackageNumber = (ushort)((p2pMessage.V2Header.MessageSize - p2pMessage.V2Header.DataPacketHeaderLength) / 1202 + 1); + } + else + { + p2pMessage.V2Header.PackageNumber = 0; + } + + } + + MessageProcessor.SendMessage(p2pMessage); + } + + + + /// + /// Returns a port number which can be used to listen for a new direct connection. + /// + /// 0 when no ports can be found + protected virtual int GetNextDirectConnectionPort(IPAddress ipAddress) + { + int portAvail = 0; + + if (Settings.PublicPortPriority == PublicPortPriority.First) + { + portAvail = TryPublicPorts(ipAddress); + + if (portAvail != 0) + { + return portAvail; + } + } + + if (portAvail == 0) + { + // Don't try all ports + for (int p = 1119, maxTry = 100; + p <= IPEndPoint.MaxPort && maxTry < 1; + p++, maxTry--) + { + Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + try + { + //s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + s.Bind(new IPEndPoint(ipAddress, p)); + //s.Bind(new IPEndPoint(IPAddress.Any, p)); + s.Close(); + return p; + } + catch (SocketException ex) + { + // Permission denied + if (ex.ErrorCode == 10048 /*Address already in use*/ || + ex.ErrorCode == 10013 /*Permission denied*/) + { + p += 100; + } + continue; // throw; + } + catch (System.Security.SecurityException) + { + break; + } + } + } + + if (portAvail == 0 && Settings.PublicPortPriority == PublicPortPriority.Last) + { + portAvail = TryPublicPorts(ipAddress); + } + + return portAvail; + } + + private int TryPublicPorts(IPAddress localIP) + { + foreach (int p in Settings.PublicPorts) + { + Socket s = null; + try + { + s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + //s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); + s.Bind(new IPEndPoint(localIP, p)); + return p; + } + catch (SocketException) + { + } + finally + { + if (s != null) + s.Close(); + } + } + return 0; + } + + #endregion + + #region Message handling methods + + #region HandleMessage + + /// + /// Handles incoming P2P Messages by extracting the inner contents and converting it to a SLP Message. + /// + /// + /// + public void HandleMessage(IMessageProcessor sender, NetworkMessage message) + { + P2PMessage p2pMessage = message as P2PMessage; + Debug.Assert(p2pMessage != null, "Message is not a P2P message in MSNSLP handler", GetType().Name); + + SLPMessage slpMessage = SLPMessage.Parse(p2pMessage.InnerBody); + + if (p2pMessage.Version == P2PVersion.P2PV1) + { + if (!(p2pMessage.Footer == 0 && p2pMessage.V1Header.SessionId == 0 && + p2pMessage.V1Header.Flags != P2PFlag.Acknowledgement && p2pMessage.V1Header.MessageSize > 0)) + { + // We don't process any p2p message because this is a SIP message handler. + return; + } + } + else if (p2pMessage.Version == P2PVersion.P2PV2) + { + if (!(p2pMessage.V2Header.SessionId == 0 && + p2pMessage.V2Header.MessageSize > 0 && p2pMessage.V2Header.TFCombination == TFCombination.First)) + { + // We don't process any p2p message because this is a SIP message handler. + return; + } + } + + if (slpMessage != null) + { + // Call the methods belonging to the content-type to handle the message + switch (slpMessage.ContentType) + { + case "application/x-msnmsgr-sessionreqbody": + OnSessionRequest(p2pMessage); + break; + case "application/x-msnmsgr-transreqbody": + OnDCRequest(p2pMessage); + break; + case "application/x-msnmsgr-transrespbody": + OnDCResponse(p2pMessage); + break; + case "application/x-msnmsgr-sessionclosebody": + OnSessionCloseRequest(p2pMessage); + break; + default: + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "Content-type not supported: " + slpMessage.ContentType, GetType().Name); + break; + } + } + } + } + + #endregion + + #region OnDCRequest + + /// + /// Called when the remote client sends us it's direct-connect capabilities. + /// A reply will be send with the local client's connectivity. + /// + /// + protected virtual void OnDCRequest(P2PMessage p2pMessage) + { + SLPMessage message = SLPMessage.Parse(p2pMessage.InnerBody); + + if (message.BodyValues.ContainsKey("Bridges") && + message.BodyValues["Bridges"].ToString().Contains("TCPv1")) + { + SLPStatusMessage slpMessage = new SLPStatusMessage(message.ToMail, 200, "OK"); + + // Initial NonceType. Remote side prefers this. But I prefer Nonce :) + DCNonceType dcNonceType; + Guid nonce = ParseDCNonce(message.BodyValues, out dcNonceType); + + if (dcNonceType == DCNonceType.None) + { + nonce = Guid.NewGuid(); + } + bool hashed = false; + string nonceFieldName = "Nonce"; + + // Find host by name + IPAddress ipAddress = LocalEndPoint.Address; + int port; + + if (p2pMessage.Version == P2PVersion.P2PV2 || + false == ipAddress.Equals(ExternalEndPoint.Address) || + (0 == (port = GetNextDirectConnectionPort(ipAddress)))) + { + slpMessage.BodyValues["Listening"] = "false"; + slpMessage.BodyValues[nonceFieldName] = Guid.Empty.ToString("B").ToUpper(System.Globalization.CultureInfo.InvariantCulture); + } + else + { + // Let's listen + MessageSession.ListenForDirectConnection(ipAddress, port, nonce, hashed); + + + slpMessage.BodyValues["Listening"] = "true"; + slpMessage.BodyValues["Capabilities-Flags"] = "1"; + slpMessage.BodyValues["IPv6-global"] = string.Empty; + slpMessage.BodyValues["Nat-Trav-Msg-Type"] = "WLX-Nat-Trav-Msg-Direct-Connect-Resp"; + slpMessage.BodyValues["UPnPNat"] = "false"; + + slpMessage.BodyValues["NeedConnectingEndpointInfo"] = "false"; + slpMessage.BodyValues["Conn-Type"] = "Direct-Connect"; + slpMessage.BodyValues["TCP-Conn-Type"] = "Direct-Connect"; + slpMessage.BodyValues[nonceFieldName] = nonce.ToString("B").ToUpper(System.Globalization.CultureInfo.InvariantCulture); + slpMessage.BodyValues["IPv4Internal-Addrs"] = ipAddress.ToString(); + slpMessage.BodyValues["IPv4Internal-Port"] = port.ToString(System.Globalization.CultureInfo.InvariantCulture); + + // check if client is behind firewall (NAT-ted) + // if so, send the public ip also the client, so it can try to connect to that ip + if (ExternalEndPoint != null && !ExternalEndPoint.Address.Equals(localEndPoint.Address)) + { + slpMessage.BodyValues["IPv4External-Addrs"] = ExternalEndPoint.Address.ToString(); + slpMessage.BodyValues["IPv4External-Port"] = port.ToString(System.Globalization.CultureInfo.InvariantCulture); + } + } + + slpMessage.BodyValues["Bridge"] = "TCPv1"; + + slpMessage.ToMail = message.FromMail; + slpMessage.FromMail = message.ToMail; + slpMessage.Branch = message.Branch; + slpMessage.CSeq = 1; + slpMessage.CallId = message.CallId; + slpMessage.MaxForwards = 0; + slpMessage.ContentType = "application/x-msnmsgr-transrespbody"; + + P2PMessage p2pReplyMessage = new P2PMessage(Version); + p2pReplyMessage.InnerMessage = slpMessage; + + if (Version == P2PVersion.P2PV2) + { + p2pReplyMessage.V2Header.TFCombination = TFCombination.First; + p2pReplyMessage.V2Header.PackageNumber = P2PTransferSession.GetNextSLPStatusDataPacketNumber(p2pMessage.V2Header.PackageNumber); + } + + // and notify the remote client that he can connect + MessageProcessor.SendMessage(p2pReplyMessage); + + MessageSession.DCHandshakeAckV2 = p2pReplyMessage; + } + } + + #endregion + + #region OnDCResponse + + /// + /// Called when the remote client send us it's direct-connect capabilities + /// + /// + protected virtual void OnDCResponse(P2PMessage p2pMessage) + { + SLPMessage message = SLPMessage.Parse(p2pMessage.InnerBody); + MimeDictionary bodyValues = message.BodyValues; + //MSNSLPTransferProperties properties = GetTransferProperties(message.CallId); + + DCNonceType dcNonceType; + Guid nonce = ParseDCNonce(message.BodyValues, out dcNonceType); + + if (dcNonceType == DCNonceType.Sha1) + { + // Always needed + //properties.RemoteNonce = nonce; + //properties.DCNonceType = dcNonceType; + } + + + // Check the protocol + if (bodyValues.ContainsKey("Bridge") && + bodyValues["Bridge"].ToString().IndexOf("TCPv1") >= 0 && + bodyValues.ContainsKey("Listening") && + bodyValues["Listening"].ToString().ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf("true") >= 0) + { + if (dcNonceType == DCNonceType.Plain) + { + // Only needed for listening side + //properties.Nonce = nonce; + //properties.DCNonceType = dcNonceType; + } + + IPEndPoint selectedPoint = SelectIPEndPoint(bodyValues); + if (selectedPoint != null) + { + // We must connect to the remote client + ConnectivitySettings settings = new ConnectivitySettings(); + settings.Host = selectedPoint.Address.ToString(); + settings.Port = selectedPoint.Port; + + MessageSession.CreateDirectConnection(settings.Host, settings.Port, nonce, (dcNonceType == DCNonceType.Sha1)); + } + } + } + + private IPEndPoint SelectIPEndPoint(MimeDictionary bodyValues) + { + List ipAddrs = new List(); + string[] addrs = new string[0]; + int port = 0; + + if (bodyValues.ContainsKey("IPv4External-Addrs") || bodyValues.ContainsKey("srddA-lanretxE4vPI")) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, + "Using external IP addresses", GetType().Name); + + if (bodyValues.ContainsKey("IPv4External-Addrs")) + { + addrs = bodyValues["IPv4External-Addrs"].Value.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + port = int.Parse(bodyValues["IPv4External-Port"].ToString(), System.Globalization.CultureInfo.InvariantCulture); + } + else + { + char[] revHost = bodyValues["srddA-lanretxE4vPI"].ToString().ToCharArray(); + Array.Reverse(revHost); + addrs = new string(revHost).Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + + char[] revPort = bodyValues["troP-lanretxE4vPI"].ToString().ToCharArray(); + Array.Reverse(revPort); + port = int.Parse(new string(revPort), System.Globalization.CultureInfo.InvariantCulture); + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, + String.Format("{0} external IP addresses found, with port {1}", addrs.Length, port), GetType().Name); + + for (int i = 0; i < addrs.Length; i++) + { + IPAddress ip; + if (IPAddress.TryParse(addrs[i], out ip)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "\t" + addrs[i], GetType().Name); + + ipAddrs.Add(ip); + + if (ip.Equals(LocalEndPoint.Address)) + { + // External IP matches our own, clearing external IPs + //addrs = new string[0]; + //ipAddrs.Clear(); + break; + } + } + } + } + + if ((ipAddrs.Count == 0) && + (bodyValues.ContainsKey("IPv4Internal-Addrs") || bodyValues.ContainsKey("srddA-lanretnI4vPI"))) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, + "Using internal IP addresses", GetType().Name); + + if (bodyValues.ContainsKey("IPv4Internal-Addrs")) + { + addrs = bodyValues["IPv4Internal-Addrs"].Value.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + port = int.Parse(bodyValues["IPv4Internal-Port"].ToString(), System.Globalization.CultureInfo.InvariantCulture); + } + else + { + char[] revHost = bodyValues["srddA-lanretnI4vPI"].ToString().ToCharArray(); + Array.Reverse(revHost); + addrs = new string(revHost).Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + + char[] revPort = bodyValues["troP-lanretnI4vPI"].ToString().ToCharArray(); + Array.Reverse(revPort); + port = int.Parse(new string(revPort), System.Globalization.CultureInfo.InvariantCulture); + } + } + + if (addrs.Length == 0) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "Unable to find any remote IP addresses", GetType().Name); + + // Failed + return null; + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, + String.Format("{0} internal IP addresses found, with port {1}", + addrs.Length, port), GetType().Name); + + for (int i = 0; i < addrs.Length; i++) + { + IPAddress ip; + if (IPAddress.TryParse(addrs[i], out ip)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "\t" + addrs[i], GetType().Name); + + ipAddrs.Add(ip); + } + } + + if (addrs.Length == 0) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "Unable to find any remote IP addresses", GetType().Name); + + // Failed + return null; + } + + // Try to find the correct IP + IPAddress ipAddr = null; + byte[] localBytes = LocalEndPoint.Address.GetAddressBytes(); + + foreach (IPAddress ip in ipAddrs) + { + if (ip.AddressFamily == AddressFamily.InterNetwork) + { + // This is an IPv4 address + // Check if the first 3 octets match our local IP address + // If so, make use of that address (it's on our LAN) + + byte[] bytes = ip.GetAddressBytes(); + + if ((bytes[0] == localBytes[0]) && (bytes[1] == localBytes[1]) && (bytes[2] == localBytes[2])) + { + ipAddr = ip; + break; + } + } + } + + if (ipAddr == null) + ipAddr = ipAddrs[0]; + + return new IPEndPoint(ipAddr, port); + } + + + + #endregion + + #region OnSessionRequest + /// + /// Called when a remote client request a session + /// + protected virtual void OnSessionRequest(P2PMessage p2pMessage) + { + SLPMessage message = SLPMessage.Parse(p2pMessage.InnerBody); + SLPStatusMessage slpStatus = message as SLPStatusMessage; + + #region SLP Status Response (Response for receive file request, accept activity request and send display image request.) + + if (slpStatus != null) + { + if (slpStatus.CSeq == 1 && slpStatus.Code == 603) + { + OnSessionCloseRequest(p2pMessage); + } + else if (slpStatus.CSeq == 1 && slpStatus.Code == 200) + { + Guid callGuid = message.CallId; + MSNSLPTransferProperties properties = GetTransferProperties(callGuid); + + if (properties == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Cannot find request transfer property, Guid: " + callGuid.ToString("B")); + return; + } + + P2PTransferSession session = ((P2PMessageSession)MessageProcessor).GetTransferSession(properties.SessionId); + + if (session == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Cannot find request transfer session, SessionId: " + properties.SessionId.ToString()); + return; + } + + + #region File and Activity are invitor send + + int waitCounter = 0; + Timer timer = new Timer(1000); + timer.Elapsed += delegate(object sender, ElapsedEventArgs e) + { + if (waitCounter < directConnectionExpireInterval / 1000) + { + waitCounter++; + return; + } + + timer.Stop(); + timer = null; + + switch (properties.DataType) + { + case DataTransferType.File: + + // We can receive the OK message. + // We can now send the invitation to setup a transfer connection + if (MessageSession.DirectConnected == false && MessageSession.DirectConnectionAttempt == false) + SendDCInvitation(properties); + + session.StartDataTransfer(false); + + break; + + case DataTransferType.Activity: + if (session.DataStream != null && session.IsSender) + { + session.StartDataTransfer(false); + } + break; + } + }; + + timer.Start(); + #endregion + + + } + return; + } + + #endregion + + #region SLP INVITE (Request for file receiving and send display image) + + SLPRequestMessage slpMessage = message as SLPRequestMessage; + + if (slpMessage.Method == "INVITE") + { + // create a properties object and add it to the transfer collection + MSNSLPTransferProperties properties = ParseInvitationMessage(message); + + // create a p2p transfer + P2PTransferSession transferSession = new P2PTransferSession(Version, properties, MessageSession); + transferSession.TransferFinished += delegate + { + transferSession.SendDisconnectMessage(SLPRequestMessage.CreateClosingMessage(properties)); + }; + + if (Version == P2PVersion.P2PV2) + { + transferSession.DataPacketNumber = p2pMessage.V2Header.PackageNumber; + } + + // hold a reference to this argument object because we need the accept property later + MSNSLPInvitationEventArgs invitationArgs = + new MSNSLPInvitationEventArgs(properties, message, transferSession, this); + + if (properties.DataType == DataTransferType.Unknown) // If type is unknown, we reply an internal error. + { + + transferSession.SendMessage(SLPStatusMessage.CreateInternalErrorMessage(properties)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Unknown p2p datatype received: " + + properties.DataTypeGuid + ". 500 INTERNAL ERROR send.", GetType().ToString()); + return; + } + + if (properties.DataType == DataTransferType.File) + { + // set the filetransfer values in the EventArgs object. + // see the SendInvitation(..) method for more info about the layout of the context string + MemoryStream memStream = new MemoryStream(Convert.FromBase64String(message.BodyValues["Context"].ToString())); + BinaryReader reader = new BinaryReader(memStream); + reader.ReadInt32(); // previewDataLength, 4 + reader.ReadInt32(); // first flag, 4 + invitationArgs.FileSize = reader.ReadInt64(); // 8 + reader.ReadInt32(); // 2nd flag, 4 + + MemoryStream filenameStream = new MemoryStream(); + byte val = 0; + while (reader.BaseStream.Position < reader.BaseStream.Length - 2 && + (val = reader.ReadByte()) > 0) + { + filenameStream.WriteByte(val); + filenameStream.WriteByte(reader.ReadByte()); + } + invitationArgs.Filename = System.Text.UnicodeEncoding.Unicode.GetString(filenameStream.ToArray()); + } + else if (properties.DataType == DataTransferType.DisplayImage || + properties.DataType == DataTransferType.Emoticon) + { + // create a MSNObject based upon the send context + invitationArgs.MSNObject = new MSNObject(); + invitationArgs.MSNObject.SetContext(properties.Context, false); + } + else if (properties.DataType == DataTransferType.Activity) + { + if (message.BodyValues.ContainsKey("Context")) + { + string activityContextString = message.BodyValues["Context"].Value; + ActivityInfo info = new ActivityInfo(activityContextString); + invitationArgs.Activity = info; + } + } + + OnTransferInvitationReceived(invitationArgs); + + if (!invitationArgs.DelayProcess) + { + // check whether the client programmer wants to accept or reject this message + if (invitationArgs.Accept == false) + { + RejectTransfer(invitationArgs); + return; + } + + AcceptTransfer(invitationArgs); + } + } + + #endregion + + } + + #endregion + + #region OnSessionCloseRequest + + /// + /// Called when a remote client closes a session. + /// + protected virtual void OnSessionCloseRequest(P2PMessage p2pMessage) + { + SLPMessage message = SLPMessage.Parse(p2pMessage.InnerBody); + + Guid callGuid = message.CallId; + MSNSLPTransferProperties properties = GetTransferProperties(callGuid); + + if (properties != null) // Closed before or never accepted? + { + properties.SessionCloseState--; + P2PTransferSession session = MessageSession.GetTransferSession(properties.SessionId); + + if (session == null) + return; + + // remove the resources + RemoveTransferSession(session); + // and close the connection + if (session.MessageSession.DirectConnected) + session.MessageSession.CloseDirectConnection(); + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "Warning: a session with the call-id " + callGuid + " not exists.", GetType().Name); + } + } + + #endregion + + #endregion + } +}; diff --git a/MSNPSharp/DataTransfer/MSNSLPInvitationEventArgs.cs b/MSNPSharp/DataTransfer/MSNSLPInvitationEventArgs.cs new file mode 100644 index 0000000..07e8527 --- /dev/null +++ b/MSNPSharp/DataTransfer/MSNSLPInvitationEventArgs.cs @@ -0,0 +1,226 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; + +namespace MSNPSharp.DataTransfer +{ + /// + /// Used as event argument when an invitation is received. + /// + /// + /// The client programmer must set the Accept property to true (accept) or false (reject) to response + /// to the invitation. By default the invitation is rejected. + /// + [Serializable] + public class MSNSLPInvitationEventArgs : EventArgs + { + private MSNSLPTransferProperties transferProperties; + private SLPMessage invitationMessage; + private ActivityInfo activity; + private MSNObject msnObject; + private string filename; + private long fileSize; + private bool accept; + private bool delayprocess; + + [NonSerialized] + private P2PTransferSession transferSession = null; + [NonSerialized] + private MSNSLPHandler transferhandler = null; + + + public MSNSLPInvitationEventArgs( + MSNSLPTransferProperties transferProperties, + SLPMessage invitationMessage, + P2PTransferSession transferSession, + MSNSLPHandler handler) + { + this.transferProperties = transferProperties; + this.invitationMessage = invitationMessage; + this.transferSession = transferSession; + this.transferhandler = handler; + } + + /// + /// The affected transfer session + /// + public MSNSLPTransferProperties TransferProperties + { + get + { + return transferProperties; + } + set + { + transferProperties = value; + } + } + + /// + /// The affected transfer session + /// + public SLPMessage InvitationMessage + { + get + { + return invitationMessage; + } + set + { + invitationMessage = value; + } + } + + /// + /// The activity properties. + /// + public ActivityInfo Activity + { + get + { + return activity; + } + set + { + activity = value; + } + } + + /// + /// The corresponding msnobject defined in the invitation. Only available in case of an msn object + /// transfer (image display, emoticons). + /// + /// + /// Created from the Context property of the object. + /// + public MSNObject MSNObject + { + get + { + return msnObject; + } + set + { + msnObject = value; + } + } + + /// + /// Name of the file the remote contact wants to send. Only available in case of a filetransfer session. + /// + public string Filename + { + get + { + return filename; + } + set + { + filename = value; + } + } + + /// + /// The total size of the file in bytes. Only available in case of a filetransfer session. + /// + public long FileSize + { + get + { + return fileSize; + } + set + { + fileSize = value; + } + } + + /// + /// Defines if the transfer is accepted. This must be set by the client programmer in a event handler. + /// By default this property is set to false, which means the invitation is rejected. If this + /// property is set to true, the invitation is accepted. + /// + public bool Accept + { + get + { + return accept; + } + set + { + accept = value; + } + } + + /// + /// Whether process the invitation request right after the event was fired. + /// + public bool DelayProcess + { + get + { + return delayprocess; + } + set + { + delayprocess = value; + } + } + + /// + /// The p2p transfer session that will transfer the session data. + /// + public P2PTransferSession TransferSession + { + get + { + return transferSession; + } + set + { + transferSession = value; + } + } + + /// + /// Master session (SLP Handler) + /// + public MSNSLPHandler TransferHandler + { + get + { + return transferhandler; + } + } + } +}; diff --git a/MSNPSharp/DataTransfer/MSNSLPMessage.cs b/MSNPSharp/DataTransfer/MSNSLPMessage.cs new file mode 100644 index 0000000..c64eb99 --- /dev/null +++ b/MSNPSharp/DataTransfer/MSNSLPMessage.cs @@ -0,0 +1,589 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Text; +using System.IO; +using System.Collections; +using System.Globalization; + +namespace MSNPSharp.DataTransfer +{ + using MSNPSharp; + using MSNPSharp.Core; + + /// + /// Base SLP message for SLPStatusMessage and SLPRequestMessage. + /// Usually this message is contained in a P2P Message. + /// + [Serializable] + public abstract class SLPMessage : NetworkMessage + { + private Encoding encoding = Encoding.UTF8; + private MimeDictionary mimeHeaders = new MimeDictionary(); + private MimeDictionary mimeBodies = new MimeDictionary(); + + private Guid GetEndPointIDFromMailEPIDString(string mailEPID) + { + if (mailEPID.Contains(";")) + { + return new Guid(mailEPID.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)[1]); + } + + return Guid.Empty; + } + + + protected SLPMessage() + { + Via = "MSNSLP/1.0/TLP "; + Branch = Guid.NewGuid().ToString("B").ToUpperInvariant(); + CSeq = 0; + CallId = Guid.NewGuid(); + MaxForwards = 0; + ContentType = "text/unknown"; + mimeHeaders[MimeHeaderStrings.Content_Length] = "0"; + } + + protected SLPMessage(byte[] data) + { + ParseBytes(data); + } + + protected abstract string StartLine + { + get; + set; + } + + /// + /// Defaults to UTF8 + /// + public Encoding Encoding + { + get + { + return encoding; + } + set + { + encoding = value; + } + } + + public int MaxForwards + { + get + { + return int.Parse(mimeHeaders[MimeHeaderStrings.Max_Forwards], System.Globalization.CultureInfo.InvariantCulture); + } + set + { + mimeHeaders[MimeHeaderStrings.Max_Forwards] = value.ToString(); + } + } + + public string To + { + get + { + return mimeHeaders[MimeHeaderStrings.To]; + } + } + + public string From + { + get + { + return mimeHeaders[MimeHeaderStrings.From]; + } + } + + public Guid FromEndPoint + { + get + { + string mailEpID = From.Replace("", String.Empty); + return GetEndPointIDFromMailEPIDString(mailEpID); + } + } + + public Guid ToEndPoint + { + get + { + string mailEpID = To.Replace("", String.Empty); + return GetEndPointIDFromMailEPIDString(mailEpID); + } + } + + /// + /// The contact that send the message. + /// + public string FromMail + { + get + { + return From.Replace("", String.Empty); + } + internal set + { + mimeHeaders[MimeHeaderStrings.From] = String.Format("", value); + } + } + + /// + /// The contact that receives the message. + /// + public string ToMail + { + get + { + return To.Replace("", String.Empty); + } + + internal set + { + mimeHeaders[MimeHeaderStrings.To] = String.Format("", value); + } + } + + public string Via + { + get + { + return mimeHeaders["Via"]; + } + set + { + mimeHeaders["Via"] = value; + } + } + + /// + /// The current branch this message applies to. + /// + public string Branch + { + get + { + return mimeHeaders["Via"]["branch"]; + } + set + { + mimeHeaders["Via"]["branch"] = value; + } + } + + /// + /// The sequence count of this message. + /// + public int CSeq + { + get + { + return int.Parse(mimeHeaders["CSeq"], System.Globalization.CultureInfo.InvariantCulture); + } + set + { + mimeHeaders["CSeq"] = value.ToString(); + } + } + + public Guid CallId + { + get + { + return new Guid(mimeHeaders["Call-ID"]); + } + set + { + mimeHeaders["Call-ID"] = value.ToString("B").ToUpper(System.Globalization.CultureInfo.InvariantCulture); + } + } + + public string ContentType + { + get + { + return mimeHeaders[MimeHeaderStrings.Content_Type]; + } + set + { + mimeHeaders[MimeHeaderStrings.Content_Type] = value; + } + } + + /// + /// Contains all name/value combinations of non-header fields in the message + /// + public MimeDictionary BodyValues + { + get + { + return mimeBodies; + } + } + + /// + /// Builds the entire message and returns it as a byte array. Ready to be used in a P2P Message. + /// This function adds the 0x00 at the end of the message. + /// + /// + public override byte[] GetBytes() + { + return GetBytes(true); + } + + public byte[] GetBytes(bool appendNull) + { + string body = mimeBodies.ToString(); + + // Update the Content-Length header, +1 the additional 0x00 + // mimeBodylength + \r\n\0 + mimeHeaders[MimeHeaderStrings.Content_Length] = (body.Length + (appendNull ? 3 : 2)).ToString(); + + StringBuilder builder = new StringBuilder(512); + builder.Append(StartLine.Trim()); + builder.Append("\r\n"); + builder.Append(mimeHeaders.ToString()); + builder.Append("\r\n"); + builder.Append(body); + builder.Append("\r\n"); + + // get the bytes + byte[] message = Encoding.GetBytes(builder.ToString()); + + // add the additional 0x00 + if (appendNull) + { + byte[] totalMessage = new byte[message.Length + 1]; + message.CopyTo(totalMessage, 0); + totalMessage[message.Length] = 0x00; + + return totalMessage; + } + else + { + return message; + } + } + + /// + /// Parses an MSNSLP message and stores the values in the object's fields. + /// + /// The messagedata to parse + public override void ParseBytes(byte[] data) + { + int lineLen = MSNHttpUtility.IndexOf(data, "\r\n"); + byte[] lineData = new byte[lineLen]; + Array.Copy(data, lineData, lineLen); + StartLine = Encoding.GetString(lineData).Trim(); + + byte[] header = new byte[data.Length - lineLen - 2]; + Array.Copy(data, lineLen + 2, header, 0, header.Length); + + mimeHeaders.Clear(); + int mimeEnd = mimeHeaders.Parse(header); + + byte[] body = new byte[header.Length - mimeEnd]; + Array.Copy(header, mimeEnd, body, 0, body.Length); + + mimeBodies.Clear(); + mimeBodies.Parse(body); + } + + /// + /// Textual presentation. + /// + /// + public override string ToString() + { + return Encoding.GetString(GetBytes()); + } + + public static SLPMessage Parse(byte[] data) + { + int lineLen = MSNHttpUtility.IndexOf(data, "\r\n"); + + if (lineLen < 0) + return null; + + try + { + byte[] lineData = new byte[lineLen]; + Array.Copy(data, lineData, lineLen); + string line = Encoding.UTF8.GetString(lineData); + + if (!line.Contains("MSNSLP")) + return null; + + if (line.StartsWith("MSNSLP/1.0")) + return new SLPStatusMessage(data); + else + return new SLPRequestMessage(data); + } + catch + { + return null; + } + } + } + + /// + /// The MSNSLP INVITE (request to create transfer), + /// BYE (request to close transfer), + /// ACK message (request for acknowledgement). + /// + public class SLPRequestMessage : SLPMessage + { + string method = "UNKNOWN"; + string version = "MSNSLP/1.0"; + + public string Method + { + get + { + return method; + } + set + { + method = value; + } + } + + public string Version + { + get + { + return version; + } + set + { + version = value; + } + } + + protected override string StartLine + { + get + { + return String.Format("{0} {1}:{2} {3}", method, "MSNMSGR", ToMail, version); + } + set + { + string[] chunks = value.Split(new string[] { " ", "\r\n" }, StringSplitOptions.RemoveEmptyEntries); + + method = chunks[0]; + version = chunks[2]; + } + } + + public SLPRequestMessage(string to, string method) + : base() + { + this.ToMail = to; + this.method = method; + } + + public SLPRequestMessage(byte[] data) + : base(data) + { + } + + + /// + /// Creates a message which is send directly after the last data message. + /// + /// + public static SLPRequestMessage CreateClosingMessage(MSNSLPTransferProperties transferProperties) + { + SLPRequestMessage slpMessage = new SLPRequestMessage(transferProperties.RemoteContactEPIDString, MSNSLPRequestMethod.BYE); + slpMessage.ToMail = transferProperties.RemoteContactEPIDString; + slpMessage.FromMail = transferProperties.LocalContactEPIDString; + + slpMessage.Branch = transferProperties.LastBranch; + slpMessage.CSeq = 0; + slpMessage.CallId = transferProperties.CallId; + slpMessage.MaxForwards = 0; + slpMessage.ContentType = "application/x-msnmsgr-sessionclosebody"; + + slpMessage.BodyValues["SessionID"] = transferProperties.SessionId.ToString(System.Globalization.CultureInfo.InvariantCulture); + + if (transferProperties.DataType == DataTransferType.Activity) + { + slpMessage.BodyValues["Context"] = "dAMAgQ=="; + + } + + return slpMessage; + } + + + } + + /// + /// The MSNSLP OK, Decline, Internal Error message. + /// + public class SLPStatusMessage : SLPMessage + { + string version = "MSNSLP/1.0"; + int code = 0; + string phrase = "Unknown"; + + public int Code + { + get + { + return code; + } + set + { + code = value; + } + } + + public string Phrase + { + get + { + return phrase; + } + set + { + phrase = value; + } + } + + public string Version + { + get + { + return version; + } + set + { + version = value; + } + } + + protected override string StartLine + { + get + { + return string.Format("{0} {1} {2}", version, code, phrase); + } + set + { + string[] chunks = value.Split(new string[] { " ", "\r\n" }, StringSplitOptions.RemoveEmptyEntries); + + version = chunks[0]; + int.TryParse(chunks[1], out code); + phrase = string.Empty; + + for (int i = 2; i < chunks.Length; i++) + phrase += chunks[i] + " "; + + phrase = phrase.Trim(); + } + } + + public SLPStatusMessage(string to, int code, string phrase) + : base() + { + this.ToMail = to; + this.code = code; + this.phrase = phrase; + } + + public SLPStatusMessage(byte[] data) + : base(data) + { + } + + + /// + /// Creates an 500 internal error message. + /// + /// + /// + public static SLPStatusMessage CreateInternalErrorMessage(MSNSLPTransferProperties transferProperties) + { + SLPStatusMessage slpMessage = new SLPStatusMessage(transferProperties.RemoteContactEPIDString, 500, "Internal Error"); + slpMessage.ToMail = transferProperties.RemoteContactEPIDString; + slpMessage.FromMail = transferProperties.LocalContactEPIDString; + slpMessage.Branch = transferProperties.LastBranch; + slpMessage.CSeq = transferProperties.LastCSeq; + slpMessage.CallId = transferProperties.CallId; + slpMessage.MaxForwards = 0; + slpMessage.ContentType = "application/x-msnmsgr-sessionreqbody"; + slpMessage.BodyValues["SessionID"] = transferProperties.SessionId.ToString(System.Globalization.CultureInfo.InvariantCulture); + slpMessage.BodyValues["SChannelState"] = "0"; + return slpMessage; + } + + /// + /// Creates a 200 OK message. This is called by the handler after the client-programmer + /// has accepted the invitation. + /// + /// + public static SLPStatusMessage CreateAcceptanceMessage(MSNSLPTransferProperties properties) + { + SLPStatusMessage newMessage = new SLPStatusMessage(properties.RemoteContactEPIDString, 200, "OK"); + newMessage.ToMail = properties.RemoteContactEPIDString; + newMessage.FromMail = properties.LocalContactEPIDString; + newMessage.Branch = properties.LastBranch; + newMessage.CSeq = 1; + newMessage.CallId = properties.CallId; + newMessage.ContentType = "application/x-msnmsgr-sessionreqbody"; + newMessage.BodyValues["SessionID"] = properties.SessionId.ToString(System.Globalization.CultureInfo.InvariantCulture); + return newMessage; + } + + /// + /// Creates a 603 Decline message. + /// + /// + public static SLPStatusMessage CreateDeclineMessage(MSNSLPTransferProperties properties) + { + SLPStatusMessage newMessage = new SLPStatusMessage(properties.RemoteContactEPIDString, 603, "Decline"); + newMessage.ToMail = properties.RemoteContactEPIDString; + newMessage.FromMail = properties.LocalContactEPIDString; + newMessage.Branch = properties.LastBranch; + newMessage.CSeq = 1; + newMessage.CallId = properties.CallId; + newMessage.ContentType = "application/x-msnmsgr-sessionreqbody"; + newMessage.BodyValues["SessionID"] = properties.SessionId.ToString(System.Globalization.CultureInfo.InvariantCulture); + return newMessage; + } + } +}; diff --git a/MSNPSharp/DataTransfer/MSNSLPTransferProperties.cs b/MSNPSharp/DataTransfer/MSNSLPTransferProperties.cs new file mode 100644 index 0000000..5f55e36 --- /dev/null +++ b/MSNPSharp/DataTransfer/MSNSLPTransferProperties.cs @@ -0,0 +1,450 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Text; +using System.Diagnostics; +using System.Globalization; + +namespace MSNPSharp.DataTransfer +{ + using MSNPSharp; + using MSNPSharp.Core; + + /// + /// Holds all properties for a single data transfer. + /// + [Serializable] + public class MSNSLPTransferProperties + { + private Contact localContact = null; + private Guid localContactEndPointID = Guid.Empty; + private Contact remoteContact = null; + private Guid remoteContactEndPointID = Guid.Empty; + private P2PVersion transferStackVersion = P2PVersion.P2PV1; + + private uint sessionId = 0; + private bool remoteInvited = false; + private int sessionCloseState = (int)SessionCloseState.None; + + private int lastCSeq = 0; + private Guid nonce = Guid.Empty; + private Guid hashedNonce = Guid.Empty; + private Guid remoteNonce = Guid.Empty; + private Guid callId = Guid.Empty; + private DCNonceType dcNonceType = DCNonceType.Plain; + private string lastBranch = Guid.Empty.ToString("B").ToUpper(CultureInfo.InvariantCulture); + + private uint dataSize = 0; + private string dataTypeGuid = String.Empty; + private DataTransferType dataType = DataTransferType.Unknown; + private string context = String.Empty; + private string checksum = String.Empty; + + + protected MSNSLPTransferProperties() + { + } + + public MSNSLPTransferProperties(Contact local, Guid localEndPointID, Contact remote, Guid remoteEndPointID) + { + remoteContact = remote; + localContact = local; + localContactEndPointID = localEndPointID; + remoteContactEndPointID = remoteEndPointID; + + transferStackVersion = JudgeP2PStackVersion(local, localContactEndPointID, remote, remoteContactEndPointID, false); + } + + /// + /// The the local contact in the transfer session. + /// + public Contact LocalContact + { + get + { + return localContact; + } + } + + /// + /// The id of local contact that involved in the transfer. + /// + public Guid LocalContactEndPointID + { + get + { + return localContactEndPointID; + } + } + + /// + /// The the remote contact in the transfer session. + /// + public Contact RemoteContact + { + get + { + return remoteContact; + } + } + + /// + /// The id of remote contact that involved in the transfer. + /// + public Guid RemoteContactEndPointID + { + get + { + return remoteContactEndPointID; + } + } + + public string LocalContactEPIDString + { + get + { + if (TransferStackVersion == P2PVersion.P2PV1) + { + return LocalContact.Mail.ToLowerInvariant(); + } + + return LocalContact.Mail.ToLowerInvariant() + ";" + LocalContactEndPointID.ToString("B").ToLowerInvariant(); + } + } + + public string RemoteContactEPIDString + { + get + { + if (TransferStackVersion == P2PVersion.P2PV1) + { + return RemoteContact.Mail.ToLowerInvariant(); + } + + return RemoteContact.Mail.ToLowerInvariant() + ";" + RemoteContactEndPointID.ToString("B").ToLowerInvariant(); + } + } + + /// + /// The transfer stack that transfer layer (P2PMessageSession) used for this data transfer. + /// + public P2PVersion TransferStackVersion + { + get + { + return transferStackVersion; + } + } + + /// + /// The unique session id for the transfer + /// + public uint SessionId + { + get + { + return sessionId; + } + set + { + sessionId = value; + } + } + + /// + /// Defines whether the remote client has invited the transfer (true) or the local client has + /// initiated the transfer (false). + /// + public bool RemoteInvited + { + get + { + return remoteInvited; + } + set + { + remoteInvited = value; + } + } + + /// + /// Indicates whether we should remove this transfer session from its transferlayer (P2PMessageSession). + /// + internal SessionCloseState SessionCloseState + { + get + { + return (SessionCloseState)sessionCloseState; + } + + set + { + sessionCloseState = (int)value; + } + } + + /// + /// CSeq identifier + /// + public int LastCSeq + { + get + { + return lastCSeq; + } + set + { + lastCSeq = value; + } + } + + public DCNonceType DCNonceType + { + get + { + return dcNonceType; + } + set + { + dcNonceType = value; + } + } + + /// + /// The Nonce used in the handshake message for direct connections. + /// + public Guid Nonce + { + get + { + return nonce; + } + set + { + nonce = value; + } + } + + /// + /// The Hashed-Nonce used in the handshake message for direct connections. This is SHA1 value of + /// if remote contact supports hashed-guids, otherwise this is Guid.Empty. + /// + public Guid HashedNonce + { + get + { + return hashedNonce; + } + set + { + hashedNonce = value; + } + } + + /// + /// The remote user's Hashed-Nonce used in the handshake message for direct connections. + /// + public Guid RemoteNonce + { + get + { + return remoteNonce; + } + set + { + remoteNonce = value; + } + } + + /// + /// The unique call id for this transfer + /// + public Guid CallId + { + get + { + return callId; + } + set + { + callId = value; + } + } + + /// + /// The branch last received in the message session + /// + public string LastBranch + { + get + { + return lastBranch; + } + set + { + lastBranch = value; + } + } + + /// + /// The total length of the data, in bytes + /// + public uint DataSize + { + get + { + return dataSize; + } + set + { + dataSize = value; + } + } + + /// + /// The kind of data that will be transferred + /// + public DataTransferType DataType + { + get + { + return dataType; + } + set + { + dataType = value; + } + } + + internal string DataTypeGuid + { + get + { + return dataTypeGuid; + } + set + { + dataTypeGuid = value; + } + } + + /// + /// The context send in the invitation. This informs the client about the type of transfer, + /// filename, file-hash, msn object settings, etc. + /// + public string Context + { + get + { + return context; + } + set + { + context = value; + } + } + + /// + /// The checksum of the fields used in the context + /// + public string Checksum + { + get + { + return checksum; + } + set + { + checksum = value; + } + } + + + internal static P2PVersion JudgeP2PStackVersion( + Contact local, Guid localEPID, + Contact remote, Guid remoteEPID, + bool dumpJudgeProcedure) + { + P2PVersion result = P2PVersion.P2PV1; + + if (!local.EndPointData.ContainsKey(localEPID)) + { + string errorMessage = "Invalid parameter localEndPointID, EndPointData with id = " + + localEPID.ToString("B") + " not exists in contact: " + local; + Trace.WriteLineIf(Settings.TraceSwitch.TraceError && dumpJudgeProcedure, "[JudgeP2PStackVersion] " + errorMessage); + + } + + if (!remote.EndPointData.ContainsKey(remoteEPID)) + { + string errorMessage = "Invalid parameter remoteEndPointID, EndPointData with id = " + + remoteEPID.ToString("B") + " not exists in contact: " + remote; + Trace.WriteLineIf(Settings.TraceSwitch.TraceError && dumpJudgeProcedure, "[JudgeP2PStackVersion] " + errorMessage); + } + + bool supportMPOP = (localEPID != Guid.Empty && remoteEPID != Guid.Empty); + + if (local.EndPointData.ContainsKey(localEPID) && remote.EndPointData.ContainsKey(remoteEPID)) + { + bool supportMSNC10 = ((local.EndPointData[localEPID].ClientCapacities & ClientCapacities.CanHandleMSNC10) > 0 && + (remote.EndPointData[remoteEPID].ClientCapacities & ClientCapacities.CanHandleMSNC10) > 0); + bool supportP2Pv2 = ((local.EndPointData[localEPID].ClientCapacitiesEx & ClientCapacitiesEx.SupportsPeerToPeerV2) > 0 && + (remote.EndPointData[remoteEPID].ClientCapacitiesEx & ClientCapacitiesEx.SupportsPeerToPeerV2) > 0); + + + + if (supportMPOP /*&& supportP2Pv2 && supportMSNC10 */) //It seems that supportP2Pv2 is not a consideration. + result = P2PVersion.P2PV2; + else + result = P2PVersion.P2PV1; + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose && dumpJudgeProcedure, + "Version Triggers: supportMPOP = " + supportMPOP + ", supportMSNC10 = " + supportMSNC10 + ", supportP2Pv2 = " + supportP2Pv2 + ", Result = " + result); + } + else + { + + if (localEPID != Guid.Empty && remoteEPID != Guid.Empty) + { + result = P2PVersion.P2PV2; + } + + result = P2PVersion.P2PV1; + + Trace.WriteLineIf(Settings.TraceSwitch.TraceError && dumpJudgeProcedure, "[JudgeP2PStackVersion] Judge only based on EPIDs, result:" + result); + } + + return result; + } + } +}; diff --git a/MSNPSharp/DataTransfer/P2PDCPool.cs b/MSNPSharp/DataTransfer/P2PDCPool.cs new file mode 100644 index 0000000..efa8c86 --- /dev/null +++ b/MSNPSharp/DataTransfer/P2PDCPool.cs @@ -0,0 +1,129 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace MSNPSharp.DataTransfer +{ + using MSNPSharp; + using MSNPSharp.Core; + + /// + /// A pool for P2P Direct-connection messages. + /// + /// + /// This message pool will read in the first 4 bytes for the length of the message. And after that the + /// lenth is read and inserted in a buffer. + /// + public class P2PDCPool : MSNPSharp.Core.MessagePool + { + private Queue messages = Queue.Synchronized(new Queue()); + private byte[] lastMessage; + private int bytesLeft; + + /// + /// Constructor. + /// + public P2PDCPool() + { + } + + /// + /// Buffers incoming P2P direct connected messages. + /// + /// + public override void BufferData(System.IO.BinaryReader reader) + { + lock (reader.BaseStream) + { + // make sure we read the last retrieved message if available + if (bytesLeft > 0 && lastMessage != null) + { + // make sure no overflow occurs + int length = (int)Math.Min(bytesLeft, (uint)(reader.BaseStream.Length - reader.BaseStream.Position)); + reader.Read(lastMessage, lastMessage.Length - bytesLeft, (int)length); + bytesLeft -= length; + + + if (bytesLeft == 0) + { + // insert it into the temporary buffer for later retrieval + messages.Enqueue(lastMessage); + lastMessage = null; + } + } + + + while (reader.BaseStream.Position < reader.BaseStream.Length) + { + // read the length of the message + uint messageLength = reader.ReadUInt32(); + + // make sure no overflow occurs + int length = (int)Math.Min(messageLength, (uint)(reader.BaseStream.Length - reader.BaseStream.Position)); + + // read in the bytes + byte[] message = new byte[messageLength]; + reader.Read(message, 0, (int)length); + + if (length < messageLength) + { + bytesLeft = (int)messageLength - length; + lastMessage = message; + } + else + { + lastMessage = null; + + // insert it into the temporary buffer for later retrieval + messages.Enqueue(message); + } + } + } + } + + public override byte[] GetNextMessageData() + { + return (byte[])messages.Dequeue(); + } + + public override bool MessageAvailable + { + get + { + return messages.Count > 0; + } + } + } +}; diff --git a/MSNPSharp/DataTransfer/P2PDirectProcessor.cs b/MSNPSharp/DataTransfer/P2PDirectProcessor.cs new file mode 100644 index 0000000..38b4624 --- /dev/null +++ b/MSNPSharp/DataTransfer/P2PDirectProcessor.cs @@ -0,0 +1,493 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Net; +using System.Text; +using System.Net.Sockets; +using System.Diagnostics; +using System.Timers; +using Org.Mentalis.Network.ProxySocket; + +namespace MSNPSharp.DataTransfer +{ + using MSNPSharp.Core; + + public enum DirectConnectionState + { + None = 0, + Closed = 0, + Foo = 1, + Handshake = 2, + HandshakeReply = 3, + Established = 4 + } + + [Serializable] + public class P2PHandshakeMessageEventArgs : EventArgs + { + private P2PDCHandshakeMessage handshakeMessage = null; + + public P2PDCHandshakeMessage HandshakeMessage + { + get + { + return handshakeMessage; + } + } + + public P2PHandshakeMessageEventArgs(P2PDCHandshakeMessage handshakeMessage) + { + this.handshakeMessage = handshakeMessage; + } + } + + /// + /// Handles the direct connections in P2P sessions. + /// + public class P2PDirectProcessor : SocketMessageProcessor, IDisposable + { + public event EventHandler HandshakeCompleted; + + private P2PVersion version = P2PVersion.P2PV1; + private Guid nonce = Guid.Empty; + private bool needHash = false; + private Timer socketExpireTimer = new Timer(12000); + private ProxySocket socketListener = null; + private bool isListener = false; + private Socket dcSocket = null; + private DirectConnectionState dcState = DirectConnectionState.Closed; + + public P2PVersion Version + { + get + { + return version; + } + } + + public DirectConnectionState DCState + { + get + { + return dcState; + } + protected internal set + { + dcState = value; + } + } + + public Guid Nonce + { + get + { + return nonce; + } + } + + /// + /// Returns whether this processor was initiated as listening (true) or connecting (false). + /// + public bool IsListener + { + get + { + return isListener; + } + } + + /// + /// Constructor. + /// + public P2PDirectProcessor(ConnectivitySettings connectivitySettings, P2PVersion p2pVersion, Guid authNonce, bool isNeedHash) + : base(connectivitySettings) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Constructing object - " + p2pVersion, GetType().Name); + + this.version = p2pVersion; + this.nonce = authNonce; + this.needHash = isNeedHash; + this.MessagePool = new P2PDCPool(); + } + + ~P2PDirectProcessor() + { + Dispose(false); + } + + + /// + /// Starts listening at the specified port in the connectivity settings. + /// + public void Listen(IPAddress address, int port) + { + ProxySocket socket = GetPreparedSocket(address, port); + + // Begin waiting for the incoming connection + socket.Listen(1); + + // set this value so we know whether to send a handshake message or not later in the process + isListener = true; + socketListener = socket; + + socketExpireTimer.Elapsed += new ElapsedEventHandler(socketExpireTimer_Elapsed); + socketExpireTimer.AutoReset = false; + socketExpireTimer.Enabled = true; // After accepted, DISABLE timer. + socket.BeginAccept(new AsyncCallback(EndAcceptCallback), socket); + } + + private void socketExpireTimer_Elapsed(object sender, ElapsedEventArgs e) + { + socketExpireTimer.Elapsed -= socketExpireTimer_Elapsed; + + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, + "I was waiting for " + (socketExpireTimer.Interval / 1000) + " seconds, but no one has connected!", GetType().Name); + + Dispose(); + } + + private void StopListening() + { + if (socketListener != null) + { + try + { + socketListener.Close(); + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, GetType().ToString() + " Error: " + ex.Message); + } + + socketListener = null; + } + } + + /// + /// Called when an incoming connection has been accepted. + /// + /// + protected virtual void EndAcceptCallback(IAsyncResult ar) + { + ProxySocket listenSocket = (ProxySocket)ar.AsyncState; + try + { + dcSocket = listenSocket.EndAccept(ar); + + // Disable timer. Otherwise, data transfer will be broken after 12 secs. + // Huge datas can't transmit within 12 secs :) + socketExpireTimer.Enabled = false; + + dcState = DirectConnectionState.Foo; + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, + "I have listened on " + dcSocket.LocalEndPoint + " and setup a DC with " + dcSocket.RemoteEndPoint, GetType().Name); + + // Stop listening + StopListening(); + + // Begin accepting messages + BeginDataReceive(dcSocket); + + OnConnected(); + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, GetType().ToString() + " Error: " + ex.Message); + } + } + + + /// + /// Closes the socket connection. + /// + public override void Disconnect() + { + base.Disconnect(); + + StopListening(); + + // clean up the socket properly + if (dcSocket != null) + { + try + { + dcSocket.Shutdown(SocketShutdown.Both); + } + catch (Exception dcex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, dcex.Message); + } + finally + { + dcSocket.Close(); + } + + dcSocket = null; + } + } + + + protected override void OnConnected() + { + if (!IsListener && dcState == DirectConnectionState.Closed) + { + this.dcState = DirectConnectionState.Foo; + SendSocketData(new byte[] { 0x04, 0x00, 0x00, 0x00, 0x66, 0x6f, 0x6f, 0x00 }); + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "foo0 sent", GetType().Name); + + this.dcState = DirectConnectionState.Handshake; + } + + base.OnConnected(); + } + + protected override void OnDisconnected() + { + dcState = DirectConnectionState.Closed; + base.OnDisconnected(); + } + + private P2PDCHandshakeMessage VerifyHandshake(byte[] data) + { + P2PVersion authVersion = P2PVersion.P2PV1; + P2PDCHandshakeMessage ret = null; + + if (data.Length == 48) + { + authVersion = P2PVersion.P2PV1; + } + else if (data.Length == 16) + { + authVersion = P2PVersion.P2PV2; + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, + "Invalid handshake length, the data was: " + Encoding.ASCII.GetString(data), GetType().Name); + + return null; + } + + if (authVersion != this.version) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, + String.Format("Received version is {0}, expected {1}", authVersion, this.version), GetType().Name); + + return null; + } + + P2PDCHandshakeMessage incomingHandshake = new P2PDCHandshakeMessage(version); + incomingHandshake.ParseBytes(data); + + Guid incomingGuid = incomingHandshake.Guid; + + if (incomingHandshake.Version == P2PVersion.P2PV1 && (P2PFlag.DirectHandshake != (incomingHandshake.V1Header.Flags & P2PFlag.DirectHandshake))) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, + "Handshake flag not set for v1, the flag was: " + incomingHandshake.V1Header.Flags, GetType().Name); + + return null; + } + + Guid compareGuid = incomingGuid; + if (needHash) + { + compareGuid = HashedNonceGenerator.HashNonce(compareGuid); + } + + if (this.nonce == compareGuid) + { + ret = new P2PDCHandshakeMessage(version); + ret.ParseBytes(data); // copy identifiers + ret.Guid = compareGuid; // set new guid (hashed) + return ret; // OK this is our handshake message + } + + return null; + + } + + /// + /// Discards the foo message and sends the message to all handlers as a P2PDCMessage object. + /// + /// + protected override void OnMessageReceived(byte[] data) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "Analyzing message in DC state <" + dcState + ">", GetType().Name); + + switch (dcState) + { + case DirectConnectionState.Established: + { + // Convert to a p2pdc message + P2PDCMessage dcMessage = new P2PDCMessage(version); + dcMessage.ParseBytes(data); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, dcMessage.ToDebugString(), GetType().Name); + + // If request ack is wanted send ack. + if (dcMessage.Version == P2PVersion.P2PV2 && + dcMessage.V2Header.OperationCode == (byte)OperationCode.RAK) + { + SendMessage(dcMessage.CreateAcknowledgement()); + + if (!dcMessage.IsSLPData) + { + goto DISPATCH; + } + return; + } + + DISPATCH: + + lock (MessageHandlers) + { + foreach (IMessageHandler handler in MessageHandlers) + { + handler.HandleMessage(this, dcMessage); + } + } + } + break; + + case DirectConnectionState.HandshakeReply: + { + P2PDCHandshakeMessage match = VerifyHandshake(data); + + if (match == null) + { + Dispose(); + return; + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "Handshake Completed: " + match.Guid + "; My Nonce: " + this.nonce + "; Need Hash: " + needHash, GetType().Name); + + this.dcState = DirectConnectionState.Established; + OnHandshakeCompleted(new P2PHandshakeMessageEventArgs(match)); + } + break; + + case DirectConnectionState.Handshake: + { + P2PDCHandshakeMessage match = VerifyHandshake(data); + + if (match == null) + { + Dispose(); + return; + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "Handshake Completed: " + match.Guid + "; My Nonce: " + this.nonce + "; Need Hash: " + needHash, GetType().Name); + + this.dcState = DirectConnectionState.Established; + OnHandshakeCompleted(new P2PHandshakeMessageEventArgs(match)); + } + break; + + case DirectConnectionState.Foo: + { + string initialData = Encoding.ASCII.GetString(data); + + if (data.Length == 4 && initialData == "foo\0") + { + this.dcState = DirectConnectionState.Handshake; + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "foo0 handled", GetType().Name); + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "foo0 expected, but it was: " + initialData, GetType().Name); + Dispose(); + return; + } + } + break; + + case DirectConnectionState.Closed: + break; + } + + } + + + /// + /// Sends the P2PMessage directly over the socket. Accepts P2PDCMessage and P2PMessage objects. + /// + /// + public override void SendMessage(NetworkMessage message) + { + // if it is a regular message convert it + P2PDCMessage p2pMessage = message as P2PDCMessage; + if (p2pMessage == null) + { + p2pMessage = new P2PDCMessage(message as P2PMessage); + } + + // prepare the message + p2pMessage.PrepareMessage(); + + // this is very bloated! + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Outgoing message:\r\n" + p2pMessage.ToDebugString(), GetType().Name); + + if (dcSocket != null) + SendSocketData(dcSocket, p2pMessage.GetBytes()); + else + SendSocketData(p2pMessage.GetBytes()); + } + + protected virtual void OnHandshakeCompleted(P2PHandshakeMessageEventArgs e) + { + if (HandshakeCompleted != null) + HandshakeCompleted(this, e); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + Disconnect(); + } + + base.Dispose(disposing); + } + + public new void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } +}; diff --git a/MSNPSharp/DataTransfer/P2PHandler.cs b/MSNPSharp/DataTransfer/P2PHandler.cs new file mode 100644 index 0000000..c75f660 --- /dev/null +++ b/MSNPSharp/DataTransfer/P2PHandler.cs @@ -0,0 +1,775 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections; +using System.Diagnostics; + +namespace MSNPSharp.DataTransfer +{ + using MSNPSharp; + using MSNPSharp.Core; + using System.Collections.Generic; + + /// + /// Used in events where a P2PMessageSession object is created, or in another way affected. + /// + public class P2PSessionAffectedEventArgs : EventArgs + { + /// + /// + private P2PMessageSession session; + + /// + /// The affected session + /// + public P2PMessageSession Session + { + get + { + return session; + } + set + { + session = value; + } + } + + /// + /// Constructor. + /// + /// + public P2PSessionAffectedEventArgs(P2PMessageSession affectedSession) + { + session = affectedSession; + } + } + + /// + /// Handles incoming P2P messages from the switchboardserver. + /// + public class P2PHandler : IMessageHandler + { + #region Members + + private NSMessageHandler nsMessageHandler = null; + private Messenger messenger = null; + private P2PMessagePool p2pMessagePool = new P2PMessagePool(); + private List messageSessions = new List(); + private List switchboardSessions = new List(0); + + #endregion + + /// + /// Protected constructor. + /// + protected internal P2PHandler(NSMessageHandler nsHandler, Messenger parentMessenger) + { + nsMessageHandler = nsHandler; + messenger = parentMessenger; + } + + #region Properties + + /// + /// The nameserver handler. This object is used to request new switchboard sessions. + /// + internal NSMessageHandler NSMessageHandler + { + get + { + return nsMessageHandler; + } + } + + /// + /// The message processor that will send the created P2P messages to the remote contact. + /// + [Obsolete("This is always null. Don't use!", true)] + public IMessageProcessor MessageProcessor + { + get + { + return null; + } + set + { + } + } + + /// + /// A list of all current p2p message sessions. Multiple threads can access this resource so make sure to lock this. + /// + public List MessageSessions + { + get + { + return messageSessions; + } + } + + /// + /// A collection of all available switchboard sessions + /// + internal List SwitchboardSessions + { + get + { + return switchboardSessions; + } + } + + #endregion + + /// + /// Aborts and cleans up all running messagesessions, transfersessions and switchboard sessions. + /// + public void Clear() + { + lock (MessageSessions) + { + foreach (P2PMessageSession session in MessageSessions) + { + session.CleanUp(); + } + } + + lock (MessageSessions) + MessageSessions.Clear(); + + lock (switchboardSessions) + switchboardSessions.Clear(); + + p2pMessagePool = new P2PMessagePool(); + } + + #region Events + + /// + /// Occurs when a P2P session is created. + /// + public event EventHandler SessionCreated; + + /// + /// Occurs when a P2P session is closed. + /// + public event EventHandler SessionClosed; + + /// + /// Fires the SessionCreated event. + /// + /// + protected virtual void OnSessionCreated(P2PMessageSession session) + { + if (SessionCreated != null) + SessionCreated(this, new P2PSessionAffectedEventArgs(session)); + } + + /// + /// Fires the SessionClosed event. + /// + /// + protected internal virtual void OnSessionClosed(P2PMessageSession session) + { + if (SessionClosed != null) + SessionClosed(this, new P2PSessionAffectedEventArgs(session)); + } + + #endregion + + /// + /// Gets a reference to a p2p message session with the specified remote contact. + /// In case a session does not exist a new session will be created and returned. + /// + /// + /// + /// + /// + /// + public virtual P2PMessageSession GetSession(Contact localContact, Guid localEPID, Contact remoteContact, Guid remoteEPID) + { + // check for existing session + P2PMessageSession existingSession = GetSessionByContactAndEPID(localContact, localEPID, remoteContact, remoteEPID); + + if (existingSession != null) + { + if (existingSession.MessageProcessor is SocketMessageProcessor) + { + if ((existingSession.MessageProcessor as SocketMessageProcessor).Connected) + { + return existingSession; + } + else + { + RemoveP2PMessageSession(existingSession); + } + } + } + + // no session available, create a new session + P2PMessageSession newSession = CreateSession(localContact, localEPID, remoteContact, remoteEPID, null, null); + + + return newSession; + } + + /// + /// Creates a p2p session. The session is at the moment of return pure fictive; no actual messages + /// have been sent to the remote client. The session will use the P2PHandler's messageprocessor as it's default messageprocessor. + /// + /// + /// + /// + /// + /// + /// + /// + protected virtual P2PMessageSession CreateSession(Contact localContact, Guid localEndPointID, Contact remoteContact, Guid remoteEndPointID, P2PMessage initatorMessage, IMessageProcessor sessionMessageProcessor) + { + P2PMessageSession session = new P2PMessageSession(localContact, localEndPointID, remoteContact, remoteEndPointID, NSMessageHandler); + session.MessageProcessor = sessionMessageProcessor; + session.ProcessorInvalid += OnP2PMessageSessionProcessorInvalid; + + // generate a local base identifier. + session.LocalBaseIdentifier = (uint)((new Random()).Next(10000, int.MaxValue)); + + // uses -1 because the first message must be the localbaseidentifier and the identifier + // is automatically increased + session.LocalIdentifier = (uint)session.LocalBaseIdentifier; + + if (initatorMessage != null) + { + session.RemoteBaseIdentifier = initatorMessage.Header.Identifier; + session.RemoteIdentifier = initatorMessage.Header.Identifier; + + if (initatorMessage.Version == P2PVersion.P2PV2) + { + session.RemoteIdentifier += initatorMessage.V2Header.MessageSize; + } + } + + AddP2PMessageSession(session); + + // Accepts by default owner display images and contact emoticons. + session.MasterSession.TransferInvitationReceived += delegate(object sender, MSNSLPInvitationEventArgs args) + { + if (args.TransferProperties.DataType == DataTransferType.DisplayImage) + { + args.Accept = true; + + args.TransferSession.DataStream = NSMessageHandler.ContactList.Owner.DisplayImage.OpenStream(); + args.TransferSession.AutoCloseStream = false; + args.TransferSession.ClientData = NSMessageHandler.ContactList.Owner.DisplayImage; + } + else if (args.TransferProperties.DataType == DataTransferType.Emoticon) + { + MSNObject msnObject = new MSNObject(); + msnObject.SetContext(args.TransferProperties.Context); + + // send an emoticon + foreach (Emoticon emoticon in NSMessageHandler.ContactList.Owner.Emoticons.Values) + { + if (emoticon.Sha == msnObject.Sha) + { + args.Accept = true; + args.TransferSession.AutoCloseStream = true; + args.TransferSession.DataStream = emoticon.OpenStream(); + args.TransferSession.ClientData = emoticon; + } + } + } + else + { + // forward the invitation to the client programmer + messenger.OnTransferInvitationReceived(sender, args); + } + return; + }; + + + OnSessionCreated(session); + return session; + } + + /// + /// Gets a switchboard session with the specified remote contact present in the session. Null is returned if no such session is found. + /// + /// + /// + protected SBMessageHandler GetSwitchboardForP2PMessageSession(Contact remoteContact) + { + lock (SwitchboardSessions) + { + foreach (SBMessageHandler switchboard in SwitchboardSessions) + { + if (switchboard.HasContact(remoteContact) && switchboard.IsSessionEstablished) + { + return switchboard; + } + } + return null; + } + } + + /// + /// Gets the p2p message session for which the remote identifier equals the identifier passed as a parameter. + /// This is typically called when an incoming message is processed. + /// + /// + /// + /// + /// + /// + protected P2PMessageSession GetSessionByContactAndEPID(Contact localContact, Guid localEPID, Contact remoteContact, Guid remoteEPID) + { + P2PVersion expectedStackVersion = MSNSLPTransferProperties.JudgeP2PStackVersion(localContact, localEPID, remoteContact, remoteEPID, false); + lock (MessageSessions) + { + foreach (P2PMessageSession session in MessageSessions) + { + if (session.Version == expectedStackVersion) + { + if (session.Version == P2PVersion.P2PV2) + { + if ((session.RemoteContact.IsSibling(remoteContact) && session.RemoteContactEndPointID == remoteEPID) && + (session.LocalContact.IsSibling(localContact) && session.LocalContactEndPointID == localEPID)) + return session; + } + else if (session.Version == P2PVersion.P2PV1) + { + if (session.RemoteContact.IsSibling(remoteContact) && session.LocalContact.IsSibling(localContact)) + return session; + } + } + } + } + return null; + } + + /// + /// After the first acknowledgement we must set the identifier of the remote client. + /// + /// + protected P2PMessageSession SetSessionIdentifiersAfterAck(P2PMessage receivedMessage) + { + P2PMessageSession session = (receivedMessage.Version == P2PVersion.P2PV1) + ? GetSessionFromSequenceNumber(receivedMessage.V1Header.AckSessionId) + : null; // We only do things step by step. + + if (session == null) + throw new MSNPSharpException("P2PHandler: an acknowledgement for the creation of a P2P session was received, but no local created session could be found with the specified identifier."); + + // set the remote identifiers. + session.RemoteBaseIdentifier = receivedMessage.Header.Identifier; + session.RemoteIdentifier = (uint)(receivedMessage.Header.Identifier);// - (ulong)session.RemoteInitialCorrection); + + return session; + } + + /// + /// Gets the p2p message session for which the local identifier equals the identifier passed as a parameter. + /// This is typically called when a message is created. + /// + /// The identifier used by the remote client + /// + protected P2PMessageSession GetSessionFromSequenceNumber(uint identifier) + { + lock (MessageSessions) + { + foreach (P2PMessageSession session in MessageSessions) + { + if (session.LocalIdentifier == identifier) + return session; + } + } + return null; + } + + + + #region HandleMessage + + /// + /// Handles incoming sb messages. Other messages are ignored. + /// + /// + /// + public void HandleMessage(IMessageProcessor sender, NetworkMessage message) + { + SBMessage sbMessage = message as SBMessage; + + if (sbMessage == null) + return; + + if (sbMessage.Command != "MSG") + { + return; + } + + if (NSMessageHandler.ContactList.Owner == null) + return; + + // create a MSGMessage from the sb message + MimeMessage msgMessage = new MimeMessage(); + try + { + msgMessage.CreateFromParentMessage(sbMessage); + } + catch (Exception e) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, e.ToString(), GetType().Name); + } + + // check if it's a valid p2p message (chunk messages has no content type) + if (!msgMessage.MimeHeader.ContainsKey(MimeHeaderStrings.Content_Type) || + msgMessage.MimeHeader[MimeHeaderStrings.Content_Type].ToString() != "application/x-msnmsgrp2p") + { + return; + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Parsing incoming p2p message", GetType().Name); + + P2PVersion version = P2PVersion.P2PV1; + + string remoteAccount = (sbMessage.CommandValues.Count > 0) ? sbMessage.CommandValues[0].ToString() : String.Empty; + string localAccount = NSMessageHandler.ContactList.Owner.Mail; + + Guid remoteContactEPID = Guid.Empty; + Guid localContactEPID = Guid.Empty; + + if (msgMessage.MimeHeader.ContainsKey("P2P-Dest")) + { + if (msgMessage.MimeHeader["P2P-Dest"].ToString().Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries).Length > 1) + { + version = P2PVersion.P2PV2; + remoteAccount = msgMessage.MimeHeader["P2P-Src"].ToString().Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries)[0]; + remoteContactEPID = new Guid(msgMessage.MimeHeader["P2P-Src"].ToString().Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries)[1]); + localAccount = msgMessage.MimeHeader["P2P-Dest"].ToString().Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries)[0]; + localContactEPID = new Guid(msgMessage.MimeHeader["P2P-Dest"].ToString().Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries)[1]); + + Trace.WriteLine("P2Pv2 incoming message found. P2P-Dest: " + msgMessage.MimeHeader["P2P-Dest"].ToString()); + } + else + { + localAccount = msgMessage.MimeHeader["P2P-Dest"].ToString(); + remoteAccount = msgMessage.MimeHeader.ContainsKey("P2P-Src") + ? msgMessage.MimeHeader["P2P-Src"].ToString() + : sbMessage.CommandValues[0].ToString(); // CommandValues.Count=0, Clone issue???? + + Trace.WriteLine("P2Pv1 incoming message found. P2P-Dest: " + msgMessage.MimeHeader["P2P-Dest"].ToString()); + } + } + + // Check destination + if (version == P2PVersion.P2PV2 && + localContactEPID != Guid.Empty && + localContactEPID != NSMessageHandler.MachineGuid) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "The destination of p2pv2 message received is not owner.\r\n" + + "Destination GUID: " + localContactEPID.ToString("B") + "\r\n" + + "Owner GUID: " + NSMessageHandler.MachineGuid.ToString("B")); + return; // This message is not for me + } + + // Create a P2P Message from the msg message + P2PMessage p2pMessage = new P2PMessage(version); + p2pMessage.CreateFromParentMessage(msgMessage); + + if (Settings.TraceSwitch.TraceVerbose) + { + ulong dataRemaining = 0; + + if (version == P2PVersion.P2PV1) + { + dataRemaining = p2pMessage.V1Header.TotalSize - (p2pMessage.V1Header.Offset + p2pMessage.V1Header.MessageSize); + } + else if (version == P2PVersion.P2PV2) + { + dataRemaining = p2pMessage.V2Header.DataRemaining; + } + + Trace.WriteLine("Incoming p2p message: DataRemaining: " + dataRemaining + "\r\n" + + p2pMessage.ToDebugString(), GetType().Name); + } + + // Buffer splitted P2P SLP messages. + if (p2pMessagePool.BufferMessage(ref p2pMessage)) + { + // - Buffering: Not completed yet, wait next packets... + // - Invalid packet: Just ignore it... + return; + } + + SLPMessage slp = p2pMessage.IsSLPData ? p2pMessage.InnerMessage as SLPMessage : null; + + Contact remoteContact = null; + Contact localContact = null; + + if (remoteAccount.ToLowerInvariant() == NSMessageHandler.ContactList.Owner.Mail.ToLowerInvariant()) + { + remoteContact = NSMessageHandler.ContactList.Owner; + } + else + { + if (!NSMessageHandler.ContactList.HasContact(remoteAccount, ClientType.PassportMember)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "P2P remote contact not in contact list: " + remoteAccount + " Type: " + ClientType.PassportMember.ToString()); + return; + } + + remoteContact = NSMessageHandler.ContactList.GetContact(remoteAccount, ClientType.PassportMember); + } + + if (localAccount.ToLowerInvariant() == NSMessageHandler.ContactList.Owner.Mail.ToLowerInvariant()) + localContact = NSMessageHandler.ContactList.Owner; + + P2PMessageSession session = GetSessionByContactAndEPID(localContact, localContactEPID, remoteContact, remoteContactEPID); + + if (session == null) + { + if (version == P2PVersion.P2PV1) + { + if (p2pMessage.V1Header.IsAcknowledgement) + { + // if it is an acknowledgement then the local client initiated the session. + // this means the session alread exists, but the remote identifier are not yet set. + session = SetSessionIdentifiersAfterAck(p2pMessage); + } + else + { + // there is no session available at all. the remote client sends the first message + // in the session. So create a new session to handle following messages. + session = CreateSession(NSMessageHandler.ContactList.Owner, localContactEPID, remoteContact, remoteContactEPID, p2pMessage, sender); + } + } + + if (version == P2PVersion.P2PV2) + { + // there is no session available at all. the remote client sends the first message + // in the session. So create a new session to handle following messages. + + if (slp != null) + { + SLPRequestMessage req = slp as SLPRequestMessage; + + if (req != null && + req.Method == "INVITE" && + req.ContentType == "application/x-msnmsgr-sessionreqbody") + { + session = CreateSession(NSMessageHandler.ContactList.Owner, localContactEPID, remoteContact, remoteContactEPID, p2pMessage, sender); + } + } + } + + if (session == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "P2PHandler get session failed."); + return; + } + } + + Debug.Assert(session != null, "Session is null", "P2PHandler"); + + // Send an acknowledgement after the last message + if (version == P2PVersion.P2PV1) + { + if (p2pMessage.Header.IsAcknowledgement == false && + p2pMessage.V1Header.Offset + p2pMessage.Header.MessageSize == p2pMessage.Header.TotalSize) + { + P2PMessage ack = p2pMessage.CreateAcknowledgement(); + session.SendMessage(ack); + } + } + if (version == P2PVersion.P2PV2) + { + //Case 1: 0x18 0x03 Invite + if ((p2pMessage.V2Header.OperationCode & (byte)OperationCode.RAK) > 0) + { + P2PMessage ack = p2pMessage.CreateAcknowledgement(); + session.SendMessage(ack); + } + } + + // now handle the message + session.HandleMessage(sender, p2pMessage); + + } + + #endregion + + internal virtual bool AddP2PMessageSession(P2PMessageSession session) + { + lock (MessageSessions) + { + if (MessageSessions.Contains(session)) + return false; + + MessageSessions.Add(session); + return true; + } + } + + + /// + /// Add a switchboard handler to the list of switchboard sessions to send messages to. + /// + /// + internal virtual bool AddSwitchboardSession(SBMessageHandler session) + { + lock (SwitchboardSessions) + { + if (SwitchboardSessions.Contains(session) == false) + { + SwitchboardSessions.Add(session); + return true; + } + } + + return false; + } + + internal virtual bool RemoveP2PMessageSession(P2PMessageSession session) + { + lock (MessageSessions) + { + return MessageSessions.Remove(session); + } + } + + /// + /// Removes a switchboard handler from the list of switchboard sessions to send messages to. + /// + /// + internal virtual bool RemoveSwitchboardSession(SBMessageHandler session) + { + int remainCount = 0; + bool succeed = true; + lock (SwitchboardSessions) + { + succeed = SwitchboardSessions.Remove(session); + remainCount = SwitchboardSessions.Count; + } + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "A " + session.GetType().ToString() + " has been removed."); + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "There is/are " + remainCount.ToString() + " switchboard(s) remain(s) unclosed."); + + return succeed; + } + + /// + /// Closes a message session. + /// + /// + protected virtual void CloseMessageSession(P2PMessageSession session) + { + // make sure there are no sessions and references left + session.AbortAllTransfers(); + session.CleanUp(); + + // call the event + OnSessionClosed(session); + + // and remove the session from the list + RemoveP2PMessageSession(session); + } + + /// + /// Requests a new switchboard session. + /// + /// + /// + private void OnP2PMessageSessionProcessorInvalid(object sender, EventArgs e) + { + P2PMessageSession session = (P2PMessageSession)sender; + + // create a new switchboard to fill the hole + SBMessageHandler sbHandler = GetSwitchboardForP2PMessageSession(session.RemoteContact); + + // if the contact is offline, there is no need to request a new switchboard. close the session. + if (session.RemoteContact.Status == PresenceStatus.Offline) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "[OnP2PMessageSessionProcessorInvalid]" + session.RemoteContact + " is already offline, P2PMessageSession closed."); + CloseMessageSession(session); + return; + } + + // check whether the switchboard handler is valid. Otherwise request a new switchboard session. + if (sbHandler == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "[OnP2PMessageSessionProcessorInvalid] A " + session.GetType().ToString() + "\r\n" + + " with remote contact " + session.RemoteContact + "\r\n" + + " and local contact " + session.LocalContact + "\r\n" + + " is requesting a new switchboard as its processor..."); + + Conversation conversation = messenger.CreateConversation(); + try + { + sbHandler = conversation.Invite(session.RemoteContact); + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "[OnP2PMessageSessionProcessorInvalid] Invite party to Conversation failed.\r\n" + + " with remote contact " + session.RemoteContact + "\r\n" + + " and local contact " + session.LocalContact + "\r\n" + + ex.Message); + Clear(); + return; + } + + //Note: for conversation's ContactJoined event, you will never see different endpoints' joining events. + //So we need to listen to the corresponding events from switchboard. + sbHandler.ContactJoined += delegate(object conv, ContactConversationEventArgs args) + { + if ((!session.ProcessorValid) && args.Contact.IsSibling(session.RemoteContact) && args.EndPoint == session.RemoteContactEndPointID) + { + session.MessageProcessor = conversation.Switchboard.MessageProcessor; + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "A " + session.GetType().ToString() + "\r\n" + + " with remote contact " + session.RemoteContact + "\r\n" + + " and local contact " + session.LocalContact + "\r\n" + + " successfully request a new switchboard as its processor: " + sbHandler); + } + }; + } + else + { + //Set processor, trigger the SendBuffer(). + session.MessageProcessor = sbHandler.MessageProcessor; + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "A " + session.GetType().ToString() + "\r\n" + + " with remote contact " + session.RemoteContact + "\r\n" + + " and local contact " + session.LocalContact + "\r\n" + + " has switched its processor to another switchboard: " + sbHandler); + } + } + } +}; diff --git a/MSNPSharp/DataTransfer/P2PHeader.cs b/MSNPSharp/DataTransfer/P2PHeader.cs new file mode 100644 index 0000000..54e802c --- /dev/null +++ b/MSNPSharp/DataTransfer/P2PHeader.cs @@ -0,0 +1,963 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; + +namespace MSNPSharp.DataTransfer +{ + using MSNPSharp.Core; + + [Flags] + public enum TFCombination : byte + { + None = 0, + First = 1, + Unknown2 = 2, + MsnObject = 4, + FileTransfer = 6, + } + + [Serializable] + public abstract class P2PHeader + { + /// + /// Header length + /// + public abstract int HeaderLength + { + get; + } + + /// + /// Sequence number + /// + public UInt32 Identifier + { + get + { + return _identifier; + } + set + { + _identifier = value; + } + } + + /// + /// Payload length + /// + public UInt32 MessageSize + { + get + { + return _messageSize; + } + set + { + _messageSize = value; + } + } + + /// + /// Total size + /// + public UInt64 TotalSize + { + get + { + return _totalSize; + } + set + { + _totalSize = value; + } + } + + public UInt32 SessionId + { + get + { + return _sessionId; + } + set + { + _sessionId = value; + } + } + + /// + /// Acknowledgement identifier + /// + public abstract UInt32 AckIdentifier + { + get; + set; + } + + public abstract bool IsAcknowledgement + { + get; + } + + public abstract bool IsNegativeAck + { + get; + } + + public abstract bool RequireAck + { + get; + } + + public abstract P2PHeader CreateAck(); + public abstract int ParseHeader(byte[] data); + public abstract byte[] GetBytes(); + + protected P2PHeader() + { + } + + private UInt32 _identifier; + private UInt64 _totalSize; + private UInt32 _messageSize; + private UInt32 _sessionId; + }; + + [Serializable] + public class P2Pv1Header : P2PHeader + { + //private UInt32 sessionId; + //private UInt32 identifier; + private UInt64 offset; + //private UInt64 totalSize; + //private UInt32 messageSize; + private P2PFlag flags; + private UInt32 ackSessionId; + private UInt32 ackIdentifier; + private UInt64 ackTotalSize; + + #region Properties + + /// + /// The session identifier field. Bytes 0-3 in the binary header. + /// + public new uint SessionId + { + get + { + return base.SessionId; + } + set + { + base.SessionId = value; + } + } + + /// + /// The identifier of this message. Bytes 5-8 in the binary header. + /// + public new uint Identifier + { + get + { + return base.Identifier; + } + set + { + base.Identifier = value; + } + } + + /// + /// The offset in bytes from the begin of the total message. Bytes 9-16 in the binary header. + /// + public ulong Offset + { + get + { + return offset; + } + set + { + offset = value; + } + } + + /// + /// Total message length in bytes. Bytes 17-24 in the binary header. + /// + public new ulong TotalSize + { + get + { + return base.TotalSize; + } + set + { + base.TotalSize = value; + } + } + + /// + /// Message length in bytes of the current message. Bytes 25-28 in the binary header. + /// + public new uint MessageSize + { + get + { + return base.MessageSize; + } + set + { + base.MessageSize = value; + } + } + + /// + /// Flag parameter. Bytes 29-32 in the binary header. + /// + public P2PFlag Flags + { + get + { + return flags; + } + set + { + flags = value; + } + } + + /// + /// Acknowledge session identifier. Acknowledgement messages respond with this number in their acknowledge identfier. Bytes 33-36 in the binary header. + /// + public uint AckSessionId + { + get + { + return ackSessionId; + } + set + { + ackSessionId = value; + } + } + + /// + /// Acknowledge identifier. Set when the message is an acknowledgement to a received message. Bytes 37-40 in the binary header. + /// + public override uint AckIdentifier + { + get + { + return ackIdentifier; + } + set + { + ackIdentifier = value; + } + } + + /// + /// Acknowledged total message length. Set when the message is an acknowledgement to a received message. Bytes 41-48 in the binary header. + /// + public ulong AckTotalSize + { + get + { + return ackTotalSize; + } + set + { + ackTotalSize = value; + } + } + + + + public override int HeaderLength + { + get + { + return 48; + } + } + + public override bool IsAcknowledgement + { + get + { + return (AckIdentifier != 0) && + ((Flags & P2PFlag.Acknowledgement) == P2PFlag.Acknowledgement); + } + } + + public override bool IsNegativeAck + { + get + { + return (AckIdentifier != 0) && + ((Flags & P2PFlag.NegativeAck) == P2PFlag.NegativeAck); + } + } + + public override bool RequireAck + { + get + { + if (IsAcknowledgement) + return false; + + if ((MessageSize + Offset) == TotalSize) + return true; + + return false; + } + } + + #endregion + + public override P2PHeader CreateAck() + { + P2Pv1Header ack = new P2Pv1Header(); + ack.SessionId = SessionId; + ack.TotalSize = 0; + ack.Flags = P2PFlag.Acknowledgement; + ack.AckSessionId = Identifier; + ack.AckIdentifier = AckSessionId; + ack.AckTotalSize = TotalSize; + return ack; + } + + public override int ParseHeader(byte[] data) + { + Stream memStream = new MemoryStream(data); + BinaryReader reader = new BinaryReader(memStream); + + SessionId = (UInt32)BitUtility.ToLittleEndian(reader.ReadUInt32()); + Identifier = (UInt32)BitUtility.ToLittleEndian(reader.ReadUInt32()); + Offset = (UInt64)BitUtility.ToLittleEndian(reader.ReadUInt64()); + TotalSize = (UInt64)BitUtility.ToLittleEndian(reader.ReadUInt64()); + MessageSize = (UInt32)BitUtility.ToLittleEndian(reader.ReadUInt32()); + Flags = (P2PFlag)(UInt32)BitUtility.ToLittleEndian(reader.ReadUInt32()); + AckSessionId = (UInt32)BitUtility.ToLittleEndian(reader.ReadUInt32()); + AckIdentifier = (UInt32)BitUtility.ToLittleEndian(reader.ReadUInt32()); + AckTotalSize = (UInt64)BitUtility.ToLittleEndian(reader.ReadUInt64()); + + reader.Close(); + memStream.Close(); + + return HeaderLength; + } + + public override byte[] GetBytes() + { + byte[] header = new byte[HeaderLength]; + Stream memStream = new MemoryStream(header); + BinaryWriter writer = new BinaryWriter(memStream); + + writer.Write(BitUtility.ToLittleEndian((UInt32)SessionId)); + writer.Write(BitUtility.ToLittleEndian((UInt32)Identifier)); + writer.Write(BitUtility.ToLittleEndian((UInt64)Offset)); + writer.Write(BitUtility.ToLittleEndian((UInt64)TotalSize)); + writer.Write(BitUtility.ToLittleEndian((UInt32)MessageSize)); + writer.Write(BitUtility.ToLittleEndian((UInt32)Flags)); + writer.Write(BitUtility.ToLittleEndian((UInt32)AckSessionId)); + writer.Write(BitUtility.ToLittleEndian((UInt32)AckIdentifier)); + writer.Write(BitUtility.ToLittleEndian((UInt64)AckTotalSize)); + + writer.Close(); + memStream.Close(); + + return header; + } + + public override string ToString() + { + return "[P2Pv1Header]\r\n" + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "SessionId : {1:x} ({0})\r\n", SessionId.ToString(System.Globalization.CultureInfo.InvariantCulture), SessionId) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "Identifier : {1:x} ({0})\r\n", Identifier.ToString(System.Globalization.CultureInfo.InvariantCulture), Identifier) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "Offset : {1:x} ({0})\r\n", Offset.ToString(System.Globalization.CultureInfo.InvariantCulture), Offset) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "TotalSize : {1:x} ({0})\r\n", TotalSize.ToString(System.Globalization.CultureInfo.InvariantCulture), TotalSize) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "MessageSize : {1:x} ({0})\r\n", MessageSize.ToString(System.Globalization.CultureInfo.InvariantCulture), MessageSize) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "Flags : {1:x} ({0})\r\n", (uint)Flags, Convert.ToString(Flags)) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "AckSessionId : {1:x} ({0})\r\n", AckSessionId.ToString(System.Globalization.CultureInfo.InvariantCulture), AckSessionId) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "AckIdentifier : {1:x} ({0})\r\n", AckIdentifier.ToString(System.Globalization.CultureInfo.InvariantCulture), AckIdentifier) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "AckTotalSize : {1:x} ({0})\r\n", AckTotalSize.ToString(System.Globalization.CultureInfo.InvariantCulture), AckTotalSize); + } + }; + + [Serializable] + public class P2Pv2Header : P2PHeader + { + private byte operationCode; + //private UInt16 messageSize; + //private UInt32 identifier; + private Dictionary headerTLVs = new Dictionary(); // BIG ENDIAN + private Dictionary dataPacketTLVs = new Dictionary(); // BIG ENDIAN + + + /// + /// Header length (dynamic). Byte 0 in the binary header. + /// + /// Min: 8, Max: 252. Padding: 4 + public override int HeaderLength + { + get + { + int length = 8; + if (headerTLVs.Count > 0) + { + // Sum TLV lengths + foreach (byte[] val in headerTLVs.Values) + { + length += 1 + 1 + val.Length; + } + // 4 bytes padding + if ((length % 4) != 0) + { + length += (4 - (length % 4)); + } + } + return length; + } + } + + /// + /// The header length for data package. + /// + public int DataPacketHeaderLength + { + get + { + if (MessageSize == 0) + return 0; + + int length = 8; + if (dataPacketTLVs.Count > 0) + { + // Sum TLV lengths + foreach (byte[] val in dataPacketTLVs.Values) + { + length += (1 + 1 + val.Length); + } + // 4 bytes padding + if ((length % 4) != 0) + { + length += (4 - (length % 4)); + } + } + return length; + } + } + + /// + /// Type, Length, Values. Max length (t+l+v): 244. Header length - 8 = TLVs length + /// + public Dictionary HeaderTLVs + { + get + { + return headerTLVs; + } + } + + public Dictionary DataPacketTLVs + { + get + { + return dataPacketTLVs; + } + } + + /// + /// Operation code. Byte 1 in the binary header. + /// + public byte OperationCode + { + get + { + return operationCode; + } + set + { + operationCode = value; + } + } + + /// + /// Payload size. Bytes 2-4 in the binary header. + /// + public new uint MessageSize + { + get + { + return base.MessageSize; + } + set + { + base.MessageSize = value; + } + } + + /// + /// Message identifier. Bytes 5-8 in the binary header. + /// + public new uint Identifier + { + get + { + return base.Identifier; + } + set + { + base.Identifier = value; + } + } + + private UInt32 ackIdentifier; + + /// + /// The Identifier we acknowledge to. + /// + public override UInt32 AckIdentifier + { + get + { + if (ackIdentifier == 0 && headerTLVs.ContainsKey(0x2)) + { + ackIdentifier = BitUtility.ToUInt32(headerTLVs[0x2], 0, false); + } + return ackIdentifier; + } + set + { + ackIdentifier = value; + + if (value == 0) + { + headerTLVs.Remove(0x2); + } + else + { + headerTLVs[0x2] = BitUtility.GetBytes(value, false); + } + } + } + + private UInt32 nakIdentifier; + public virtual uint NakIdentifier + { + get + { + if (nakIdentifier == 0 && headerTLVs.ContainsKey(0x3)) + { + nakIdentifier = BitUtility.ToUInt32(headerTLVs[0x3], 0, false); + } + return nakIdentifier; + } + set + { + nakIdentifier = value; + + if (value == 0) + { + headerTLVs.Remove(0x3); + } + else + { + headerTLVs[0x3] = BitUtility.GetBytes(value, false); + } + } + } + + + public override bool IsAcknowledgement + { + get + { + return headerTLVs.ContainsKey(0x2); + } + } + + public override bool IsNegativeAck + { + get + { + return headerTLVs.ContainsKey(0x3); + } + } + + public override bool RequireAck + { + get + { + return ((OperationCode & (byte)MSNPSharp.OperationCode.RAK) > 0); + } + } + + private TFCombination tfCombination; + public TFCombination TFCombination + { + get + { + return tfCombination; + } + set + { + tfCombination = value; + } + } + + private ushort packageNumber; + public ushort PackageNumber + { + get + { + return packageNumber; + } + set + { + packageNumber = value; + } + } + + private ulong dataRemaining; + public UInt64 DataRemaining + { + get + { + if (dataRemaining == 0 && dataPacketTLVs.ContainsKey(0x1)) + { + dataRemaining = BitUtility.ToUInt64(dataPacketTLVs[0x1], 0, false); + } + return dataRemaining; + } + set + { + dataRemaining = value; + + if (value == 0) + { + dataPacketTLVs.Remove(0x1); + } + else + { + dataPacketTLVs[0x1] = BitUtility.GetBytes(value, false); + } + } + } + + public void AppendPeerInfoTLV() + { + OperationCode |= (byte)MSNPSharp.OperationCode.SYN; + HeaderTLVs[0x1] = CreatePeerInfoValue(); + } + + public override P2PHeader CreateAck() + { + P2Pv2Header ack = new P2Pv2Header(); + if ((OperationCode & (byte)MSNPSharp.OperationCode.RAK) > 0) + { + ack.AckIdentifier = Identifier + MessageSize; + ack.OperationCode = (byte)MSNPSharp.OperationCode.None; + + if (MessageSize > 0) + { + if (!IsAcknowledgement) + { + if ((OperationCode & (byte)MSNPSharp.OperationCode.SYN) != 0) + { + ack.OperationCode |= (byte)MSNPSharp.OperationCode.RAK; + + if (HeaderTLVs.ContainsKey(0x01)) + { + ack.HeaderTLVs.Add(0x01, HeaderTLVs[0x01]); //If this is an ACK, we MUST copy the peer info TLV. + ack.OperationCode |= (byte)MSNPSharp.OperationCode.SYN; + } + } + } + } + } + else + { + throw new MSNPSharpException("This P2Pv2 message do not need to be acknowledged."); + } + + return ack; + } + + /// + /// Parse header + /// + /// + /// Header length + public override int ParseHeader(byte[] data) + { + MemoryStream mem = new MemoryStream(data); + BinaryReader reader = new BinaryReader(mem); + + int headerLen = (int)(Byte)reader.ReadByte(); + OperationCode = /*(OperationCode)*/(Byte)reader.ReadByte(); + MessageSize = (uint)(UInt16)BitUtility.ToBigEndian(reader.ReadUInt16()); + Identifier = (uint)(UInt32)BitUtility.ToBigEndian(reader.ReadUInt32()); + if (headerLen > 8) //TLVs + { + byte[] TLvs = reader.ReadBytes(headerLen - 8); + int index = 0; + do + { + byte T = TLvs[index]; + + if (T == 0x0) + break; // Skip padding bytes + + byte L = TLvs[index + 1]; + byte[] V = new byte[(int)L]; + Array.Copy(TLvs, index + 2, V, 0, (int)L); + ProcessHeaderTLVData(T, L, V); + index += 2 + L; + } + while (index < TLvs.Length); + } + + mem.Seek(headerLen, SeekOrigin.Begin); + int dataHeaderLen = 0; + + if (MessageSize > 0) + { + dataHeaderLen = (int)(Byte)reader.ReadByte(); + TFCombination = (TFCombination)(Byte)reader.ReadByte(); + PackageNumber = (ushort)(UInt16)BitUtility.ToBigEndian(reader.ReadUInt16()); + SessionId = (uint)(UInt32)BitUtility.ToBigEndian(reader.ReadUInt32()); + if (dataHeaderLen > 8) //TLVs + { + byte[] TLvs = reader.ReadBytes(dataHeaderLen - 8); + int index = 0; + do + { + byte T = TLvs[index]; + + if (T == 0x0) + break; // Skip padding bytes + + byte L = TLvs[index + 1]; + byte[] V = new byte[(int)L]; + Array.Copy(TLvs, index + 2, V, 0, (int)L); + ProcessDataPacketTLVData(T, L, V); + index += 2 + L; + } + while (index < TLvs.Length); + } + + mem.Seek(headerLen + dataHeaderLen, SeekOrigin.Begin); // Skip padding bytes for TLVs + } + + reader.Close(); + mem.Close(); + + return headerLen + dataHeaderLen; + } + + protected void ProcessHeaderTLVData(byte T, byte L, byte[] V) + { + headerTLVs[T] = V; + + switch (T) + { + case 1: + // PeerInfo + if (L == 12) + { + return; + } + return; + + case 2: + if (L == 4) + { + AckIdentifier = BitUtility.ToUInt32(V, 0, false); + return; + } + break; + + case 3: + if (L == 4) + { + NakIdentifier = BitUtility.ToUInt32(V, 0, false); + return; + } + break; + } + } + + protected void ProcessDataPacketTLVData(byte T, byte L, byte[] V) + { + dataPacketTLVs[T] = V; + + switch (T) + { + case 1: + if (L == 8) + { + DataRemaining = BitUtility.ToUInt64(V, 0, false); + return; + } + break; + + case 2: + return; + } + } + + protected byte[] CreatePeerInfoValue() + { + MemoryStream peerInfoStream = new MemoryStream(0); + peerInfoStream.Write(BitUtility.GetBytes((ushort)P2PConst.ProtocolVersion, true), 0, sizeof(ushort)); + peerInfoStream.Write(BitUtility.GetBytes((ushort)P2PConst.ImplementationID, true), 0, sizeof(ushort)); + peerInfoStream.Write(BitUtility.GetBytes((ushort)P2PConst.PeerInfoVersion, true), 0, sizeof(ushort)); + peerInfoStream.Write(BitUtility.GetBytes((ushort)P2PConst.PeerInfoReservedField, true), 0, sizeof(ushort)); + peerInfoStream.Write(BitUtility.GetBytes((uint)P2PConst.Capabilities, true), 0, sizeof(uint)); + + return peerInfoStream.ToArray(); + + } + + public override byte[] GetBytes() + { + int headerLen = HeaderLength; + int dataHeaderLen = DataPacketHeaderLength; + + byte[] data = new byte[headerLen + dataHeaderLen]; + MemoryStream memStream = new MemoryStream(data); + BinaryWriter writer = new BinaryWriter(memStream); + + writer.Write((byte)headerLen); + writer.Write((byte)OperationCode); + + writer.Write(BitUtility.ToBigEndian((ushort)MessageSize)); + writer.Write(BitUtility.ToBigEndian((uint)Identifier)); + + foreach (KeyValuePair keyvalue in headerTLVs) + { + writer.Write((byte)keyvalue.Key); // Type + writer.Write((byte)keyvalue.Value.Length); // Length + writer.Write(keyvalue.Value, 0, keyvalue.Value.Length); // Value + } + + memStream.Seek(headerLen, SeekOrigin.Begin); + + if (dataHeaderLen > 0) + { + writer.Write((byte)dataHeaderLen); + writer.Write((byte)TFCombination); + writer.Write(BitUtility.ToBigEndian((ushort)PackageNumber)); + writer.Write(BitUtility.ToBigEndian((uint)SessionId)); + + foreach (KeyValuePair keyvalue in dataPacketTLVs) + { + writer.Write((byte)keyvalue.Key); // Type + writer.Write((byte)keyvalue.Value.Length); // Length + writer.Write(keyvalue.Value, 0, keyvalue.Value.Length); // Value + } + + memStream.Seek(headerLen + dataHeaderLen, SeekOrigin.Begin); // Skip padding bytes for TLVs + } + + writer.Close(); + memStream.Close(); + + return data; + } + + public override string ToString() + { + StringBuilder headerTLVBuilder = new StringBuilder(); + + headerTLVBuilder.Append(String.Format(System.Globalization.CultureInfo.InvariantCulture, "Header TLVs ({0}) : ", headerTLVs.Count.ToString(System.Globalization.CultureInfo.InvariantCulture))); + if (headerTLVs.Count > 0) + { + foreach (KeyValuePair keyvalue in headerTLVs) + { + headerTLVBuilder.Append(String.Format(System.Globalization.CultureInfo.InvariantCulture, "{1:x}({0}),", keyvalue.Key.ToString(System.Globalization.CultureInfo.InvariantCulture), keyvalue.Key)); + headerTLVBuilder.Append(String.Format(System.Globalization.CultureInfo.InvariantCulture, "{1:x}({0}),( ", keyvalue.Value.Length.ToString(System.Globalization.CultureInfo.InvariantCulture), keyvalue.Value.Length)); + foreach (byte b in keyvalue.Value) + { + headerTLVBuilder.Append(String.Format(System.Globalization.CultureInfo.InvariantCulture, "0x{0:x2} ", b)); + } + headerTLVBuilder.Append("); "); + + } + } + headerTLVBuilder.Append("\r\n"); + + StringBuilder bodyTLVBuilder = new StringBuilder(); + + bodyTLVBuilder.Append(String.Format(System.Globalization.CultureInfo.InvariantCulture, " DataPacket TLVs ({0}): ", dataPacketTLVs.Count.ToString(System.Globalization.CultureInfo.InvariantCulture))); + if (dataPacketTLVs.Count > 0) + { + foreach (KeyValuePair keyvalue in dataPacketTLVs) + { + bodyTLVBuilder.Append(String.Format(System.Globalization.CultureInfo.InvariantCulture, "{1:x}({0}),", keyvalue.Key.ToString(System.Globalization.CultureInfo.InvariantCulture), keyvalue.Key)); + bodyTLVBuilder.Append(String.Format(System.Globalization.CultureInfo.InvariantCulture, "{1:x}({0}),( ", keyvalue.Value.Length.ToString(System.Globalization.CultureInfo.InvariantCulture), keyvalue.Value.Length)); + foreach (byte b in keyvalue.Value) + { + bodyTLVBuilder.Append(String.Format(System.Globalization.CultureInfo.InvariantCulture, "0x{0:x2} ", b)); + } + bodyTLVBuilder.Append("); "); + } + } + bodyTLVBuilder.Append("\r\n"); + + int dataHeaderLen = DataPacketHeaderLength; + + return "[P2Pv2Header]\r\n" + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "HeaderLength : {1:x} ({0})\r\n", HeaderLength.ToString(System.Globalization.CultureInfo.InvariantCulture), HeaderLength) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "OperationCode : {1:x} ({0})\r\n", (byte)OperationCode, Convert.ToString(OperationCode)) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "MessageSize : {1:x} ({0})\r\n", MessageSize.ToString(System.Globalization.CultureInfo.InvariantCulture), MessageSize) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "Identifier : {1:x} ({0})\r\n", Identifier.ToString(System.Globalization.CultureInfo.InvariantCulture), Identifier) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "AckIdentifier : {1:x} ({0})\r\n", AckIdentifier.ToString(System.Globalization.CultureInfo.InvariantCulture), AckIdentifier) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "NakIdentifier : {1:x} ({0})\r\n", NakIdentifier.ToString(System.Globalization.CultureInfo.InvariantCulture), NakIdentifier) + + headerTLVBuilder.ToString() + + + String.Format(System.Globalization.CultureInfo.InvariantCulture, " Data HeaderLength : {1:x} ({0})\r\n", dataHeaderLen.ToString(System.Globalization.CultureInfo.InvariantCulture), dataHeaderLen) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, " TFCombination : {1:x} ({0})\r\n", (byte)TFCombination, Convert.ToString(TFCombination)) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, " PackageNumber : {1:x} ({0})\r\n", PackageNumber.ToString(System.Globalization.CultureInfo.InvariantCulture), PackageNumber) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, " SessionId : {1:x} ({0})\r\n", SessionId.ToString(System.Globalization.CultureInfo.InvariantCulture), SessionId) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, " DataRemaining : {1:x} ({0})\r\n", DataRemaining.ToString(System.Globalization.CultureInfo.InvariantCulture), DataRemaining) + + bodyTLVBuilder.ToString(); + } + } +}; diff --git a/MSNPSharp/DataTransfer/P2PMessage.cs b/MSNPSharp/DataTransfer/P2PMessage.cs new file mode 100644 index 0000000..09c203b --- /dev/null +++ b/MSNPSharp/DataTransfer/P2PMessage.cs @@ -0,0 +1,817 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Text; +using System.Diagnostics; +using System.Collections.Generic; + +namespace MSNPSharp.DataTransfer +{ + using MSNPSharp; + using MSNPSharp.Core; + + #region P2PMessage + + /// + /// Represents a single P2P framework message. + /// + [Serializable] + public class P2PMessage : NetworkMessage + { + private P2PVersion version = P2PVersion.P2PV1; + private P2PHeader header = null; + private uint footer = 0; + + public P2PMessage(P2PVersion ver) + { + version = ver; + + if (ver == P2PVersion.P2PV1) + { + header = new P2Pv1Header(); + } + else if (ver == P2PVersion.P2PV2) + { + header = new P2Pv2Header(); + } + } + + public P2PMessage(P2PMessage message) + : this(message.Version) + { + Header.SessionId = message.Header.SessionId; + Header.Identifier = message.Header.Identifier; + Header.TotalSize = message.Header.TotalSize; + Header.MessageSize = message.Header.MessageSize; + Header.AckIdentifier = message.Header.AckIdentifier; + + if (message.Version == P2PVersion.P2PV1) + { + V1Header.Offset = message.V1Header.Offset; + V1Header.Flags = message.V1Header.Flags; + V1Header.AckSessionId = message.V1Header.AckSessionId; + V1Header.AckTotalSize = message.V1Header.AckTotalSize; + } + else if (message.Version == P2PVersion.P2PV2) + { + V2Header.OperationCode = message.V2Header.OperationCode; + V2Header.TFCombination = message.V2Header.TFCombination; + V2Header.PackageNumber = message.V2Header.PackageNumber; + V2Header.DataRemaining = message.V2Header.DataRemaining; + + if (message.V2Header.HeaderTLVs.Count > 0) + { + foreach (KeyValuePair keyvalue in message.V2Header.HeaderTLVs) + { + V2Header.HeaderTLVs[keyvalue.Key] = keyvalue.Value; + } + } + if (message.V2Header.DataPacketTLVs.Count > 0) + { + foreach (KeyValuePair keyvalue in message.V2Header.DataPacketTLVs) + { + V2Header.DataPacketTLVs[keyvalue.Key] = keyvalue.Value; + } + } + } + + if (message.InnerMessage != null) + InnerMessage = message.InnerMessage; + + if (message.InnerBody != null) + InnerBody = message.InnerBody; + + Footer = message.Footer; + } + + /// + /// The p2p framework currently using. + /// + public P2PVersion Version + { + get + { + return version; + } + } + + public P2PHeader Header + { + get + { + return header; + } + private set + { + if ((Version == P2PVersion.P2PV1 && value is P2Pv1Header) + || (Version == P2PVersion.P2PV2 && value is P2Pv2Header)) + { + header = value; + } + } + } + + public P2Pv1Header V1Header + { + get + { + return (header as P2Pv1Header); + } + } + + public P2Pv2Header V2Header + { + get + { + return (header as P2Pv2Header); + } + } + + /// + /// The footer, or Application Identifier (BIG ENDIAN). + /// + public uint Footer + { + get + { + return footer; + } + set + { + footer = value; + } + } + + + /// + /// Payload data + /// + public new byte[] InnerBody + { + get + { + return base.InnerBody; + } + set + { + base.InnerBody = value; + base.InnerMessage = null; // Data changed, re-parse SLP message + + if (version == P2PVersion.P2PV1) + { + header.MessageSize = (uint)value.Length; + header.TotalSize = Math.Max(header.TotalSize, (ulong)value.Length); + } + else if (version == P2PVersion.P2PV2) + { + if (value.Length > 0) + { + header.MessageSize = (uint)value.Length; // DataPacketHeaderLength depends on MessageSize + header.MessageSize += (uint)V2Header.DataPacketHeaderLength; + + header.TotalSize = Math.Max(header.TotalSize, (ulong)value.Length); + } + else + { + header.MessageSize = 0; + header.TotalSize = 0; + } + } + } + } + + /// + /// SLP Message + /// + public new NetworkMessage InnerMessage + { + get + { + if (base.InnerMessage == null && InnerBody != null && InnerBody.Length > 0) + base.InnerMessage = SLPMessage.Parse(InnerBody); + + return base.InnerMessage; + } + set + { + this.InnerBody = value.GetBytes(); + base.InnerMessage = null; // Data changed, re-parse SLP message + } + } + + + public bool IsSLPData + { + get + { + if (Header.MessageSize > 0 && Header.SessionId == 0) + { + if ((Version == P2PVersion.P2PV1 && (V1Header.Flags == P2PFlag.Normal || V1Header.Flags == P2PFlag.MSNSLPInfo)) + || + (Version == P2PVersion.P2PV2 && (V2Header.TFCombination == TFCombination.None || V2Header.TFCombination == TFCombination.First))) + { + return true; + } + + } + return false; + } + } + + + /// + /// Creates an acknowledgement message to this message. + /// + /// + public virtual P2PMessage CreateAcknowledgement() + { + P2PMessage ack = new P2PMessage(Version); + ack.Header = Header.CreateAck(); + + if (Version == P2PVersion.P2PV1) + { + ack.Footer = Footer; //Keep the same as the message to acknowladge. + + } + + return ack; + } + + /// + /// Split big P2PMessages to transport over sb or dc. + /// + /// + /// + public P2PMessage[] SplitMessage(int maxSize) + { + uint payloadMessageSize = 0; + + if (Version == P2PVersion.P2PV1) + { + payloadMessageSize = V1Header.MessageSize; + } + + if (Version == P2PVersion.P2PV2) + { + payloadMessageSize = (uint)V2Header.MessageSize - (uint)V2Header.DataPacketHeaderLength; + } + + if (payloadMessageSize <= maxSize) + return new P2PMessage[] { this }; + + + Random rand = new Random(); + List chunks = new List(); + byte[] totalMessage = (InnerBody != null) + ? InnerBody + : InnerMessage.GetBytes(); + + long offset = 0; + + if (Version == P2PVersion.P2PV1) + { + while (offset < totalMessage.LongLength) + { + P2PMessage chunkMessage = new P2PMessage(Version); + uint messageSize = (uint)Math.Min((uint)maxSize, (totalMessage.LongLength - offset)); + byte[] chunk = new byte[messageSize]; + Array.Copy(totalMessage, (int)offset, chunk, 0, (int)messageSize); + + chunkMessage.V1Header.Flags = V1Header.Flags; + chunkMessage.V1Header.AckIdentifier = V1Header.AckIdentifier; + chunkMessage.V1Header.AckTotalSize = V1Header.AckTotalSize; + chunkMessage.V1Header.Identifier = V1Header.Identifier; + chunkMessage.V1Header.SessionId = V1Header.SessionId; + chunkMessage.V1Header.TotalSize = V1Header.TotalSize; + chunkMessage.V1Header.Offset = (ulong)offset; + chunkMessage.V1Header.MessageSize = messageSize; + chunkMessage.InnerBody = chunk; + + chunkMessage.V1Header.AckSessionId = (uint)rand.Next(50000, int.MaxValue); + chunkMessage.Footer = Footer; + + chunkMessage.PrepareMessage(); + chunks.Add(chunkMessage); + + offset += messageSize; + } + } + + + + if (Version == P2PVersion.P2PV2) + { + uint nextId = Header.Identifier; + long dataRemain = (long)V2Header.DataRemaining; + while (offset < totalMessage.LongLength) + { + P2PMessage chunkMessage = new P2PMessage(Version); + int maxDataSize = maxSize; + + if (offset == 0 && V2Header.HeaderTLVs.Count > 0) + { + foreach (KeyValuePair keyvalue in V2Header.HeaderTLVs) + { + chunkMessage.V2Header.HeaderTLVs[keyvalue.Key] = keyvalue.Value; + } + + maxDataSize = maxSize - chunkMessage.V2Header.HeaderLength; + } + + + uint dataSize = (uint)Math.Min((uint)maxDataSize, (totalMessage.LongLength - offset)); + + byte[] chunk = new byte[dataSize]; + Array.Copy(totalMessage, (int)offset, chunk, 0, (int)dataSize); + + if (offset == 0) + { + chunkMessage.V2Header.OperationCode = V2Header.OperationCode; + } + + chunkMessage.V2Header.SessionId = V2Header.SessionId; + chunkMessage.V2Header.TFCombination = V2Header.TFCombination; + chunkMessage.V2Header.PackageNumber = V2Header.PackageNumber; + + if (totalMessage.LongLength + dataRemain - (dataSize + offset) > 0) + { + chunkMessage.V2Header.DataRemaining = (ulong)(totalMessage.LongLength + dataRemain - (dataSize + offset)); + } + + if ((offset != 0) && + TFCombination.First == (V2Header.TFCombination & TFCombination.First)) + { + chunkMessage.V2Header.TFCombination = (TFCombination)(V2Header.TFCombination - TFCombination.First); + } + + chunkMessage.InnerBody = chunk; + chunkMessage.Header.Identifier = nextId; + nextId += chunkMessage.Header.MessageSize; + + chunks.Add(chunkMessage); + + offset += dataSize; + } + } + + return chunks.ToArray(); + } + + + /// + /// Returns debug info + /// + /// + public override string ToString() + { + return "[P2PMessage]\r\n" + + header.ToString() + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "FOOTER : {1:x} ({1})\r\n", Footer.ToString(System.Globalization.CultureInfo.InvariantCulture), Footer) + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "DATA : {0}\r\n", + ((InnerMessage != null) ? InnerMessage.ToString() : String.Format("Binary data: {0:D} bytes", (InnerBody == null ? 0 : InnerBody.Length)))); + } + + public static string DumpBytes(byte[] data) + { + if (data == null || data.Length == 0) + return string.Empty; + + StringBuilder sb = new StringBuilder(); + uint hexChars = 0; + + for (int i = 0; i < data.Length; i++) + { + string str = string.Format("0x{0:x2} ", data[i]).ToLower(); + + hexChars++; + + sb.Append(str); + + if ((hexChars > 0) && (hexChars % 10 == 0)) + sb.AppendLine(); + } + + return sb.ToString(); + } + + public override byte[] GetBytes() + { + return GetBytes(true); + } + + /// + /// Creates a P2P Message. This sets the MessageSize and TotalSize properly. + /// + /// + /// + public byte[] GetBytes(bool appendFooter) + { + InnerBody = GetInnerBytes(); + + byte[] allData = new byte[header.HeaderLength + header.MessageSize + (appendFooter ? 4 : 0)]; + + MemoryStream stream = new MemoryStream(allData); + BinaryWriter writer = new BinaryWriter(stream); + + writer.Write(header.GetBytes()); + writer.Write(InnerBody); + + if (appendFooter) + writer.Write(BitUtility.ToBigEndian(footer)); + + writer.Close(); + stream.Close(); + + return allData; + } + + + /// + /// Parses the given message. + /// + public override void ParseBytes(byte[] data) + { + int headerAndBodyHeaderLen = header.ParseHeader(data); + byte[] bodyAndFooter = new byte[data.Length - headerAndBodyHeaderLen]; + Array.Copy(data, headerAndBodyHeaderLen, bodyAndFooter, 0, bodyAndFooter.Length); + + Stream stream = new MemoryStream(bodyAndFooter); + BinaryReader reader = new BinaryReader(stream); + int innerBodyLen = 0; + + if (header.MessageSize > 0) + { + if (version == P2PVersion.P2PV1) + { + InnerBody = reader.ReadBytes((int)header.MessageSize); + innerBodyLen = InnerBody.Length; + } + else if (version == P2PVersion.P2PV2) + { + InnerBody = reader.ReadBytes((int)(header.MessageSize - V2Header.DataPacketHeaderLength)); + innerBodyLen = InnerBody.Length; + } + } + else + { + InnerBody = new byte[0]; + } + + if ((data.Length - (headerAndBodyHeaderLen + innerBodyLen)) >= 4) + { + footer = BitUtility.ToBigEndian(reader.ReadUInt32()); + } + + reader.Close(); + stream.Close(); + } + + /// + /// Returns the inner message as a byte array. + /// + /// + /// If the inner message is set the GetBytes() method is called upon that inner message. + /// If there is no inner message set, but the InnerBody property contains data then + /// that data is returned. + /// + /// + protected virtual byte[] GetInnerBytes() + { + + return (InnerBody != null) + ? InnerBody + : (InnerMessage != null ? InnerMessage.GetBytes() : new byte[0]); + } + }; + + #endregion + + #region P2PDataMessage + + /// + /// Represents a single P2PDataMessage which is used for the actual data transfer. No negotiation handling. + /// + /// + /// A p2p data message can be identified by looking at the footer in the P2P Message. + /// When this value is > 0 a data message is send. When this value is 0 a normal, and more complex, MSNSLPMessage is send. + /// This class is created to provide a fast way of sending messages. + /// + [Serializable] + public class P2PDataMessage : P2PMessage + { + /// + /// Constructs a P2P data message. + /// + public P2PDataMessage(P2PVersion v) + : base(v) + { + } + + public P2PDataMessage(P2PMessage copy) + : base(copy) + { + } + + /// + /// Writes 4 nul-bytes in the inner body. This message can then be used as a data preparation message. + /// + public void WritePreparationBytes() + { + InnerBody = new byte[4] { 0, 0, 0, 0 }; + } + + /// + /// Reads data from the stream and writes it to the inner body. Sets offset, total size, message size + /// and data remaining properly. + /// + /// The stream to read from + /// Maximum read length + public int WriteBytes(Stream ioStream, int maxLength) + { + ulong streamLen = (ulong)ioStream.Length; + ulong streamPos = (ulong)ioStream.Position; + int minReadable = (int)Math.Min((ulong)maxLength, (ulong)(streamLen - streamPos)); + + if (Version == P2PVersion.P2PV1) + { + V1Header.Offset = streamPos; + V1Header.TotalSize = streamLen; + } + else if (Version == P2PVersion.P2PV2) + { + // We must calculate DataRemaining before setting InnerBody for p2pv2. + // Otherwise, MessageSize will be calculated incorrectly. + V2Header.DataRemaining = (ulong)(streamLen - (streamPos + (ulong)minReadable)); + } + + InnerBody = new byte[minReadable]; + int read = ioStream.Read(InnerBody, 0, (int)minReadable); + + Debug.Assert(read == minReadable, "Calculated incorrectly?"); + + return read; + } + + public override string ToString() + { + return "[P2PDataMessage]\r\n" + base.ToString(); + } + }; + + #endregion + + #region P2PDCMessage + + /// + /// A P2P Message which is send in a direct-connection. + /// + /// + /// The innerbody contents are used as message contents (data). + /// The InnerMessage object and footer is ignored. + /// + [Serializable] + public class P2PDCMessage : P2PDataMessage + { + public P2PDCMessage(P2PVersion ver) + : base(ver) + { + } + + /// + /// Copy constructor. Creates a shallow copy of the properties of the P2PMessage. + /// + /// + public P2PDCMessage(P2PMessage message) + : base(message) + { + } + + /// + /// Writes no footer, but a 4 byte length size in front of the header. + /// + /// + public override byte[] GetBytes() + { + byte[] dataWithoutFooter = base.GetBytes(false); + byte[] p2pMessage = new byte[4 + dataWithoutFooter.Length]; + Stream memStream = new MemoryStream(p2pMessage); + BinaryWriter writer = new BinaryWriter(memStream); + writer.Write(BitUtility.ToLittleEndian((uint)dataWithoutFooter.Length)); + writer.Write(dataWithoutFooter); + writer.Close(); + memStream.Close(); + + return p2pMessage; + } + + /// + /// Parses a data message without the 4-byte length header and without a 4 byte footer. + /// + /// + public override void ParseBytes(byte[] data) + { + base.ParseBytes(data); + } + + public override string ToString() + { + return "[P2PDCMessage]\r\n" + base.ToString(); + } + }; + + #endregion + + #region P2PDCHandshakeMessage + + /// + /// A P2P Message which is send in a direct-connection. + /// + /// + /// The InnerBody is 0 length byte. + /// The InnerMessage is null. + /// + [Serializable] + public class P2PDCHandshakeMessage : P2PDCMessage + { + private Guid guid; + + /// + /// The Guid to use in the handshake message. + /// + public Guid Guid + { + get + { + return guid; + } + set + { + guid = value; + + if (Version == P2PVersion.P2PV1) + { + // Copy this guid to the last 16 bytes of this message. + // Affected fields: AckSessionId, AckIdentifier, AckTotalSize + + byte[] guidData = guid.ToByteArray(); + + V1Header.AckSessionId = BitUtility.ToUInt32(guidData, 0, BitConverter.IsLittleEndian); + V1Header.AckIdentifier = BitUtility.ToUInt32(guidData, 4, BitConverter.IsLittleEndian); + V1Header.AckTotalSize = BitUtility.ToUInt64(guidData, 8, BitConverter.IsLittleEndian); + } + } + } + + /// + /// Defaults the Flags property to 0x100. + /// + public P2PDCHandshakeMessage(P2PVersion ver) + : base(ver) + { + if (ver == P2PVersion.P2PV1) + V1Header.Flags = P2PFlag.DirectHandshake; + + InnerBody = new byte[0]; + } + + /// + /// Creates the handshake message to send in a direct connection. + /// + /// + /// + public P2PDCHandshakeMessage CreateHandshakeMessage(MSNSLPTransferProperties properties) + { + P2PDCHandshakeMessage dcMessage = new P2PDCHandshakeMessage(properties.TransferStackVersion); + dcMessage.Header.SessionId = 0; + + Debug.Assert(properties.Nonce != Guid.Empty, "Direct connection established, but no Nonce GUID is available."); + Debug.Assert(properties.SessionId != 0, "Direct connection established, but no session id is available."); + + // set the guid to use in the handshake message + dcMessage.Guid = properties.Nonce; + + return dcMessage; + } + + + /// + /// Creates an acknowledgement message to a handshake message. This will only set the flag to 0. + /// + /// + public override P2PMessage CreateAcknowledgement() + { + // re-create a copy of this message, it is just the same copy! + P2PDCMessage ackMessage = new P2PDCMessage(this); + + // set the identifier to 0 to set our own local identifier + ackMessage.Header.Identifier = 0; + return ackMessage; + } + + + public override void ParseBytes(byte[] data) + { + if (Version == P2PVersion.P2PV1) + { + base.ParseBytes(data); + + P2Pv1Header head = this.V1Header; + + Guid = new Guid( + (int)head.AckSessionId, + + (short)(head.AckIdentifier & 0x0000FFFF), + (short)((head.AckIdentifier & 0xFFFF0000) >> 16), + + (byte)((head.AckTotalSize & 0x00000000000000FF)), + (byte)((head.AckTotalSize & 0x000000000000FF00) >> 8), + (byte)((head.AckTotalSize & 0x0000000000FF0000) >> 16), + (byte)((head.AckTotalSize & 0x00000000FF000000) >> 24), + (byte)((head.AckTotalSize & 0x000000FF00000000) >> 32), + (byte)((head.AckTotalSize & 0x0000FF0000000000) >> 40), + (byte)((head.AckTotalSize & 0x00FF000000000000) >> 48), + (byte)((head.AckTotalSize & 0xFF00000000000000) >> 56) + ); + } + else + { + // Don't call base.ParseBytes(); Data is 16 bytes for v2. + Guid = HashedNonceGenerator.CreateGuidFromData(Version, data); + } + + InnerBody = new byte[0]; + } + + /// + /// Writes no footer. + /// + /// + public override byte[] GetBytes() + { + InnerBody = new byte[0]; + + byte[] guidData = guid.ToByteArray(); + + if (Version == P2PVersion.P2PV1) + { + byte[] handshakeMessage = base.GetBytes(); // Calls P2PDCMessage.GetBytes(); + + Array.Copy(guidData, 0, handshakeMessage, handshakeMessage.Length - guidData.Length, guidData.Length); + + return handshakeMessage; + } + else + { + // UINT(LE) + GUID, Don't call base.GetBytes(); Because this is 20 bytes for v2. + byte[] totalMessage = new byte[4 + 16]; + byte[] packetSize = BitUtility.GetBytes((UInt32)16, true); + + Array.Copy(packetSize, 0, totalMessage, 0, packetSize.Length); + Array.Copy(guidData, 0, totalMessage, packetSize.Length, guidData.Length); + + return totalMessage; + } + } + + public override string ToString() + { + return "[P2PDCHandshakeMessage]\r\n" + + String.Format(System.Globalization.CultureInfo.InvariantCulture, "Guid : {0}\r\n", this.Guid.ToString()) + + (Version == P2PVersion.P2PV1 ? base.ToString() : String.Empty); + + } + } + + #endregion +}; diff --git a/MSNPSharp/DataTransfer/P2PMessagePool.cs b/MSNPSharp/DataTransfer/P2PMessagePool.cs new file mode 100644 index 0000000..91dce06 --- /dev/null +++ b/MSNPSharp/DataTransfer/P2PMessagePool.cs @@ -0,0 +1,212 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Collections; +using System.Diagnostics; +using System.Collections.Generic; + +namespace MSNPSharp.DataTransfer +{ + using MSNPSharp; + using MSNPSharp.Core; + + /// + /// Buffers incompleted P2PMessage SLP messages. + /// + public class P2PMessagePool + { + private Dictionary incompletedP2PV1Messages = new Dictionary(); + private Dictionary incompletedP2PV2Messages = new Dictionary(); + + /// + /// Buffers incompleted P2PMessage SLP messages. Ignores data and control messages. + /// + /// + /// + /// true if the P2PMessage is buffering (not completed) or invalid packet received; + /// false if the p2p message fully buffered or no need to buffer. + /// + public bool BufferMessage(ref P2PMessage p2pMessage) + { + // P2PV1 and P2PV2 check + if (p2pMessage.Header.MessageSize == 0 || // Ack message or Unsplitted + p2pMessage.Header.SessionId > 0) // Data message + { + return false; // No need to buffer + } + + // P2PV2 pooling + if (p2pMessage.Version == P2PVersion.P2PV2) + { + if ((p2pMessage.V2Header.TFCombination == TFCombination.First && p2pMessage.V2Header.DataRemaining == 0) || // Unsplitted SLP message or data preparation message + (p2pMessage.V2Header.TFCombination > TFCombination.First)) // Data message + { + return false; // No need to buffer + } + + // First splitted SLP message. + if (p2pMessage.V2Header.TFCombination == TFCombination.First && + p2pMessage.V2Header.DataRemaining > 0) + { + P2PMessage totalMessage = new P2PMessage(p2pMessage); // Copy it + ulong totalSize = (ulong)(p2pMessage.V2Header.MessageSize - p2pMessage.V2Header.DataPacketHeaderLength) + + p2pMessage.V2Header.DataRemaining; + + totalMessage.InnerBody = new byte[totalSize]; // Allocate buffer as needed + Array.Copy(p2pMessage.InnerBody, 0, totalMessage.InnerBody, (long)0, (long)p2pMessage.InnerBody.Length); + + lock (incompletedP2PV2Messages) + incompletedP2PV2Messages[p2pMessage.V2Header.Identifier + p2pMessage.V2Header.MessageSize] = totalMessage; + + return true; // Buffering + } + + // Other splitted SLP messages + if (p2pMessage.V2Header.TFCombination == TFCombination.None) + { + lock (incompletedP2PV2Messages) + { + if (incompletedP2PV2Messages.ContainsKey(p2pMessage.V2Header.Identifier)) + { + if (incompletedP2PV2Messages[p2pMessage.V2Header.Identifier].V2Header.PackageNumber == p2pMessage.V2Header.PackageNumber) + { + P2PMessage totalMessage = incompletedP2PV2Messages[p2pMessage.V2Header.Identifier]; + ulong dataSize = Math.Min(((ulong)(p2pMessage.V2Header.MessageSize - p2pMessage.V2Header.DataPacketHeaderLength)), totalMessage.V2Header.DataRemaining); + ulong offSet = ((ulong)totalMessage.InnerBody.LongLength) - totalMessage.V2Header.DataRemaining; + + // Check range and buffer overflow... + if (((p2pMessage.V2Header.DataRemaining + (ulong)dataSize) == totalMessage.V2Header.DataRemaining) && + (ulong)(dataSize + offSet + p2pMessage.V2Header.DataRemaining) == (ulong)totalMessage.InnerBody.LongLength) + { + Array.Copy(p2pMessage.InnerBody, 0, totalMessage.InnerBody, (long)offSet, (long)dataSize); + uint originalIdentifier = p2pMessage.V2Header.Identifier; + uint newIdentifier = p2pMessage.V2Header.Identifier + p2pMessage.V2Header.MessageSize; + + totalMessage.V2Header.DataRemaining = p2pMessage.V2Header.DataRemaining; + totalMessage.V2Header.Identifier = newIdentifier; + + if (originalIdentifier != newIdentifier) + { + incompletedP2PV2Messages.Remove(originalIdentifier); + } + + if (p2pMessage.V2Header.DataRemaining > 0) + { + incompletedP2PV2Messages[newIdentifier] = totalMessage; + + // Don't debug p2p packet here. Because it hasn't completed yet and SLPMessage.Parse() fails... + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Buffering splitted messages and hasn't completed yet! DataRemaining:" + totalMessage.V2Header.DataRemaining); + return true; // Buffering + } + else // Last part + { + totalMessage.InnerBody = totalMessage.InnerBody; // Refresh... DataRemaining=0 deletes data headers. + totalMessage.V2Header.Identifier = newIdentifier - totalMessage.Header.MessageSize; + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, + "A splitted message was combined :\r\n" + + totalMessage.ToDebugString()); + + p2pMessage = totalMessage; + return false; // We have the whole message + } + } + } + + // Invalid packet received!!! Ignore and delete it... + incompletedP2PV2Messages.Remove(p2pMessage.V2Header.Identifier); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, + "INVALID P2PV2 PACKET received!!! Ignored and deleted:\r\n" + + p2pMessage.ToDebugString()); + } + } + } + } + else // P2PV1 pooling + { + if ((p2pMessage.V1Header.MessageSize == p2pMessage.V1Header.TotalSize) || // Whole data + ((p2pMessage.V1Header.Flags & P2PFlag.Data) == P2PFlag.Data)) // Data message + { + return false; // No need to buffer + } + + lock (incompletedP2PV1Messages) + { + if (false == incompletedP2PV1Messages.ContainsKey(p2pMessage.Header.Identifier)) + { + byte[] totalPayload = new byte[p2pMessage.V1Header.TotalSize]; + Array.Copy(p2pMessage.InnerBody, 0, totalPayload, (long)p2pMessage.V1Header.Offset, (long)p2pMessage.V1Header.MessageSize); + P2PMessage copyMessage = new P2PMessage(p2pMessage); + + copyMessage.InnerBody = totalPayload; + copyMessage.V1Header.Offset = p2pMessage.V1Header.Offset + p2pMessage.V1Header.MessageSize; + + incompletedP2PV1Messages[p2pMessage.Header.Identifier] = copyMessage; + return true; // Buffering + } + + P2PMessage totalMessage = incompletedP2PV1Messages[p2pMessage.Header.Identifier]; + if (p2pMessage.V1Header.TotalSize == totalMessage.V1Header.TotalSize && + (p2pMessage.V1Header.Offset + p2pMessage.V1Header.MessageSize) <= totalMessage.Header.TotalSize) + { + Array.Copy(p2pMessage.InnerBody, 0, totalMessage.InnerBody, (long)p2pMessage.V1Header.Offset, (long)p2pMessage.V1Header.MessageSize); + totalMessage.V1Header.Offset = p2pMessage.V1Header.Offset + p2pMessage.V1Header.MessageSize; + + // Last packet + if (totalMessage.V1Header.Offset == p2pMessage.V1Header.TotalSize) + { + totalMessage.V1Header.Offset = 0; + incompletedP2PV1Messages.Remove(p2pMessage.Header.Identifier); + + p2pMessage = totalMessage; + return false; // We have the whole message + } + + return true; // Buffering + } + + // Invalid packet received!!! Ignore and delete it... + incompletedP2PV1Messages.Remove(p2pMessage.Header.Identifier); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, + "INVALID P2PV1 PACKET received!!! Ignored and deleted:\r\n" + + p2pMessage.ToDebugString()); + } + } + + return true; // Invalid packet, don't kill me. + } + } +}; diff --git a/MSNPSharp/DataTransfer/P2PMessageSession.DC.cs b/MSNPSharp/DataTransfer/P2PMessageSession.DC.cs new file mode 100644 index 0000000..895d818 --- /dev/null +++ b/MSNPSharp/DataTransfer/P2PMessageSession.DC.cs @@ -0,0 +1,423 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Net; +using System.Text; +using System.Threading; +using System.Collections; +using System.Diagnostics; +using System.Globalization; +using System.Collections.Generic; + +namespace MSNPSharp.DataTransfer +{ + using MSNPSharp; + using MSNPSharp.Core; + + partial class P2PMessageSession + { + #region Events + + /// + /// Occurs when a direct connection is succesfully established. + /// + public event EventHandler DirectConnectionEstablished; + + /// + /// Occurs when a direct connection attempt has failed. + /// + public event EventHandler DirectConnectionFailed; + + #endregion + + // A list of all direct processors trying to establish a connection. + private List pendingProcessors = new List(); + private bool autoAcknowledgeHandshake = true; + private bool directConnectionAttempt; + private bool directConnected; + + // Tracked to know when an acknowledgement for the handshake is received. + private uint DCHandshakeAckV1; + + // Tracked to know when an acknowledgement for the handshake is received. + internal P2PMessage DCHandshakeAckV2; + + #region Properties + + /// + /// Defines whether a direct connection handshake is automatically send to the remote client, or + /// replied with an acknowledgement. Setting this to true means the remote client will start the + /// transfer immediately. Setting this to false means the client programmer must send a handhsake + /// message and an acknowledgement message after which the transfer will begin. + /// + public bool AutoHandshake + { + get + { + return autoAcknowledgeHandshake; + } + set + { + autoAcknowledgeHandshake = value; + } + } + + /// + /// Defines whether an attempt has been made to create a direct connection + /// + public bool DirectConnectionAttempt + { + get + { + return directConnectionAttempt; + } + } + + /// + /// Defines whether the message session runs over a direct session or is routed via the messaging server + /// + public bool DirectConnected + { + get + { + return directConnected; + } + } + + #endregion + + #region Public Methods + + /// + /// Creates a direct connection with the remote client. + /// + /// + public IMessageProcessor CreateDirectConnection(string host, int port, Guid nonce, bool hashed) + { + P2PDirectProcessor processor = new P2PDirectProcessor( + new ConnectivitySettings(host, port), Version, nonce, hashed); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Trying to setup direct connection with remote host " + host + ":" + port.ToString(System.Globalization.CultureInfo.InvariantCulture), GetType().Name); + + AddPendingProcessor(processor); + + processor.Connect(); + + return processor; + } + + /// + /// Setups a P2PDirectProcessor to listen for incoming connections. After a connection has been + /// established the P2PDirectProcessor will become the main MessageProcessor to send messages. + /// + /// + public IMessageProcessor ListenForDirectConnection(IPAddress host, int port, Guid nonce, bool hashed) + { + ConnectivitySettings cs = new ConnectivitySettings(); + if (NSMessageHandler.ConnectivitySettings.LocalHost == string.Empty) + { + cs.LocalHost = host.ToString(); + cs.LocalPort = port; + } + else + { + cs.LocalHost = NSMessageHandler.ConnectivitySettings.LocalHost; + cs.LocalPort = NSMessageHandler.ConnectivitySettings.LocalPort; + } + + P2PDirectProcessor processor = new P2PDirectProcessor(cs, Version, nonce, hashed); + + // add to the list of processors trying to establish a connection + AddPendingProcessor(processor); + + // start to listen + processor.Listen(IPAddress.Parse(cs.LocalHost), cs.LocalPort); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Listening on " + cs.LocalHost + ":" + cs.LocalPort.ToString(System.Globalization.CultureInfo.InvariantCulture), GetType().Name); + + return processor; + } + + /// + /// Closes the direct connection with the remote client, if available. A closing p2p message will be send first. + /// The session will fallback to the previous (SB) message processor. + /// + public void CloseDirectConnection() + { + if (DirectConnected) + { + CleanUpDirectConnection(); + } + } + + #endregion + + #region Pending Processor Methods + + /// + /// Add the processor to the pending list. + /// + /// + protected void AddPendingProcessor(P2PDirectProcessor processor) + { + // we want to handle message from this processor + processor.RegisterHandler(this); + + // inform the session of connected/disconnected events + processor.ConnectionEstablished += (OnDirectProcessorConnected); + processor.ConnectionClosed += (OnDirectProcessorDisconnected); + processor.ConnectingException += (OnDirectProcessorException); + processor.HandshakeCompleted += (OnDirectProcessorHandshakeCompleted); + + lock (pendingProcessors) + { + pendingProcessors.Add(processor); + } + } + + /// + /// Use the given processor as the DC processor. And disconnect all other pending processors. + /// + /// + protected void UsePendingProcessor(P2PDirectProcessor processor) + { + lock (pendingProcessors) + { + if (pendingProcessors.Contains(processor)) + { + pendingProcessors.Remove(processor); + } + } + + // stop all remaining attempts + StopAllPendingProcessors(); + + // set the direct processor as the main processor + lock (this) + { + directConnected = true; + directConnectionAttempt = true; + preDCProcessor = MessageProcessor; + MessageProcessor = processor; + } + + if (DirectConnectionEstablished != null) + DirectConnectionEstablished(this, EventArgs.Empty); + } + + /// + /// Disconnect all processors that are trying to establish a connection. + /// + protected void StopAllPendingProcessors() + { + lock (pendingProcessors) + { + foreach (P2PDirectProcessor processor in pendingProcessors) + { + processor.Disconnect(); + processor.UnregisterHandler(this); + } + pendingProcessors.Clear(); + } + } + + #endregion + + + /// + /// Sends the handshake message (NONCE) in a direct connection. + /// + protected virtual void SendHandshakeMessage(IMessageProcessor processor) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Preparing to send handshake message", GetType().Name); + + P2PDirectProcessor p2pDP = (P2PDirectProcessor)processor; + + if (p2pDP.Nonce == Guid.Empty) + { + // don't throw an exception because the file transfer can continue over the switchboard + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "Handshake could not be send because none is specified.", GetType().Name); + + // but close the direct connection + p2pDP.Disconnect(); + return; + } + + P2PDCHandshakeMessage hm = new P2PDCHandshakeMessage(p2pDP.Version); + hm.Guid = p2pDP.Nonce; + + if (hm.Version == P2PVersion.P2PV1) + { + IncreaseLocalIdentifier(); + + hm.Header.Identifier = LocalIdentifier; + //hm.V1Header.AckSessionId = (uint)new Random().Next(50000, int.MaxValue); + // AckSessionId is set by hm.Guid=NONCE... + DCHandshakeAckV1 = hm.V1Header.AckSessionId; + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Sending handshake message:\r\n " + + hm.ToDebugString(), GetType().Name); + + p2pDP.SendMessage(hm); + + p2pDP.DCState = DirectConnectionState.HandshakeReply; + } + + /// + /// Occurs when an acknowledgement to a send handshake has been received, or a handshake is received. + /// This will start the data transfer, provided the local client is the sender. + /// + private void OnDirectProcessorHandshakeCompleted(object sender, P2PHandshakeMessageEventArgs e) + { + P2PDirectProcessor dp = sender as P2PDirectProcessor; + P2PDCHandshakeMessage p2pMessage = e.HandshakeMessage; + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Handshake accepted", GetType().Name); + + if (p2pMessage.Version == P2PVersion.P2PV1 && p2pMessage.V1Header.Flags == P2PFlag.DirectHandshake) + { + // Check whether it is an acknowledgement to data preparation message + if (DCHandshakeAckV1 != 0) + { + UsePendingProcessor(dp); + return; + } + + // check if it's a direct connection handshake + if (AutoHandshake) + { + // create a handshake message based on the incoming p2p message and send it + dp.SendMessage(p2pMessage.CreateAcknowledgement()); + + UsePendingProcessor(dp); + return; + } + } + + if (p2pMessage.Version == P2PVersion.P2PV2) + { + if (DCHandshakeAckV2 != null) + { + DCHandshakeAckV2.V2Header.OperationCode = (byte)OperationCode.RAK; + dp.SendMessage(DCHandshakeAckV2); + DCHandshakeAckV2 = null; + + UsePendingProcessor(dp); + return; + } + + if (AutoHandshake) + { + UsePendingProcessor(dp); + } + } + } + + + /// + /// Sets the message processor back to the switchboard message processor. + /// + private void CleanUpDirectConnection() + { + if (DirectConnected) + { + lock (this) + { + SocketMessageProcessor directProcessor = (SocketMessageProcessor)MessageProcessor; + + directConnected = false; + directConnectionAttempt = false; + MessageProcessor = preDCProcessor; + + if (directProcessor != null) + directProcessor.Disconnect(); + + P2PDirectProcessor dp = directProcessor as P2PDirectProcessor; + if (dp != null) + { + dp.HandshakeCompleted -= (OnDirectProcessorHandshakeCompleted); + } + } + } + } + + /// + /// Cleans up the direct connection. + /// + private void OnDirectProcessorDisconnected(object sender, EventArgs e) + { + ((SocketMessageProcessor)sender).ConnectionClosed -= (OnDirectProcessorDisconnected); + + CleanUpDirectConnection(); + } + + + /// + /// Sets the current message processor to the processor which has just connected succesfully. + /// + /// + /// + private void OnDirectProcessorConnected(object sender, EventArgs e) + { + P2PDirectProcessor p2pdp = (P2PDirectProcessor)sender; + p2pdp.ConnectionEstablished -= (OnDirectProcessorConnected); + + if (p2pdp.IsListener == false && + AutoHandshake && + p2pdp.Nonce != Guid.Empty && + p2pdp.DCState == DirectConnectionState.Handshake) + { + SendHandshakeMessage(p2pdp); + } + } + + /// + /// Called when the direct processor could not connect. It will start the data transfer over the + /// switchboard session. + /// + /// + /// + private void OnDirectProcessorException(object sender, ExceptionEventArgs e) + { + ((SocketMessageProcessor)sender).ConnectingException -= (OnDirectProcessorException); + + CleanUpDirectConnection(); + directConnectionAttempt = true; + + if (DirectConnectionFailed != null) + DirectConnectionFailed(this, EventArgs.Empty); + } + } +}; diff --git a/MSNPSharp/DataTransfer/P2PMessageSession.cs b/MSNPSharp/DataTransfer/P2PMessageSession.cs new file mode 100644 index 0000000..d62489c --- /dev/null +++ b/MSNPSharp/DataTransfer/P2PMessageSession.cs @@ -0,0 +1,896 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Net; +using System.Text; +using System.Threading; +using System.Collections; +using System.Diagnostics; +using System.Net.Sockets; +using System.Globalization; +using System.Collections.Generic; + +namespace MSNPSharp.DataTransfer +{ + using MSNPSharp; + using MSNPSharp.Core; + + /// + /// P2PMessageSession routes all messages in the p2p framework between the local client and a single + /// remote client. It is the Transfer Layer of MSNP2P Protocol. + /// + /// + /// A single message session can hold multiple p2p transfer sessions. This for example occurs when a + /// contact sends two files directly after each other in the same switchboard session. This class keeps + /// track of the message identifiers, dispatches messages to registered message handlers and routes data + /// messages to the correct objects. Usually this class is a handler + /// of a switchboard processor. A common handler for this class is . + /// + public partial class P2PMessageSession : IMessageHandler, IMessageProcessor + { + #region Events + + /// + /// Occurs when the processor has been marked as invalid. Due to connection error, or message processor being null. + /// + public event EventHandler ProcessorInvalid; + + /// + /// Occurs when a P2P session is closed. + /// + public event EventHandler SessionClosed; + + #endregion + + #region Members + + private uint localBaseIdentifier = 0; + private uint localIdentifier = 0; + private uint remoteBaseIdentifier = 0; + private uint remoteIdentifier = 0; + private Contact remoteContact = null; + private Contact localContact = null; + private Guid localContactEndPointID = Guid.Empty; + private Guid remoteContactEndPointID = Guid.Empty; + private NSMessageHandler nsMessageHandler = null; + private P2PVersion version = P2PVersion.P2PV1; + + private MSNSLPHandler masterSession = null; + + + /// + /// Keeps track of unsend messages + /// + private Queue sendMessages = new Queue(); + + private bool processorValid = true; + + /// This is the processor used before a direct connection. Usually a SB processor. + /// It is a fallback variables in case a direct connection fails. + private IMessageProcessor preDCProcessor = null; + + /// A collection of all transfersessions + private Dictionary transferSessions = new Dictionary(); + + #endregion + + #region Constructor + + protected P2PMessageSession() + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Constructing object", GetType().Name); + } + + public P2PMessageSession(Contact local, Guid localEPID, Contact remote, Guid remoteEPID, NSMessageHandler handler) + { + version = MSNSLPTransferProperties.JudgeP2PStackVersion(local, localEPID, remote, remoteEPID, true); + + localContact = local; + localContactEndPointID = localEPID; + remoteContact = remote; + remoteContactEndPointID = remoteEPID; + + nsMessageHandler = handler; + NSMessageHandler.ContactOffline += (NSMessageHandler_ContactOffline); + + masterSession = new MSNSLPHandler(Version, NSMessageHandler.P2PInvitationSchedulerId, NSMessageHandler.ContactList.Owner.ClientIP); + masterSession.MessageProcessor = this; + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Initializing P2P Transfer Layer object, version = " + Version.ToString(), GetType().Name); + } + + + #endregion + + #region Properties + + + + public Guid LocalContactEndPointID + { + get + { + return localContactEndPointID; + } + } + + public Guid RemoteContactEndPointID + { + get + { + return remoteContactEndPointID; + } + } + + /// + /// The P2P Version of the transfer layer. + /// + public P2PVersion Version + { + get + { + return version; + } + } + + protected NSMessageHandler NSMessageHandler + { + get + { + return nsMessageHandler; + } + } + + /// + /// Get the of the transfer layer, each transfer layer have only one + /// + /// + public MSNSLPHandler MasterSession + { + get + { + return masterSession; + } + } + + /// + /// Indicates whether the processor is invalid + /// + public bool ProcessorValid + { + get + { + return processorValid; + } + } + + + /// + /// The sequence number that local transfer starts from. + /// + public uint LocalBaseIdentifier + { + get + { + return localBaseIdentifier; + } + set + { + localBaseIdentifier = value; + } + } + + /// + /// The local sequence number of transfer layer message packet. + /// + public uint LocalIdentifier + { + get + { + return localIdentifier; + } + set + { + localIdentifier = value; + } + } + + /// + /// The sequence number that remote transfer starts from. + /// + public uint RemoteBaseIdentifier + { + get + { + return remoteBaseIdentifier; + } + set + { + remoteBaseIdentifier = value; + } + } + + /// + /// The remote sequence number of transfer layer message packet. + /// + public uint RemoteIdentifier + { + get + { + return remoteIdentifier; + } + set + { + remoteIdentifier = value; + } + } + + /// + /// The account of the local contact. + /// + public Contact LocalContact + { + get + { + return localContact; + } + + } + + /// + /// The account of the remote contact. + /// + public Contact RemoteContact + { + get + { + return remoteContact; + } + + } + + private string LocalContactEPIDString + { + get + { + if (Version == P2PVersion.P2PV1) + return LocalContact.Mail.ToLowerInvariant(); + + return LocalContact.Mail.ToLowerInvariant() + ";" + LocalContactEndPointID.ToString("B").ToLowerInvariant(); + } + } + + private string RemoteContactEPIDString + { + get + { + if (Version == P2PVersion.P2PV1) + return RemoteContact.Mail.ToLowerInvariant(); + + return RemoteContact.Mail.ToLowerInvariant() + ";" + RemoteContactEndPointID.ToString("B").ToLowerInvariant(); + } + } + + + + #endregion + + #region IMessageProcessor Members + + private List handlers = new List(); + + /// + /// Registers a message handler. After registering the handler will receive incoming messages. + /// + /// + public void RegisterHandler(IMessageHandler handler) + { + if (handler != null && !handlers.Contains(handler)) + { + lock (handlers) + { + handlers.Add(handler); + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, + handler.ToString() + " added to handler list.", GetType().Name); + + } + } + } + + /// + /// Unregisters a message handler. After registering the handler will no longer receive incoming messages. + /// + /// + public void UnregisterHandler(IMessageHandler handler) + { + if (handler != null) + { + lock (handlers) + { + while (handlers.Remove(handler)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, + handler.ToString() + " removed from handler list.", GetType().Name); + } + } + } + } + + /// + /// Sends incoming p2p messages to the remote contact. + /// + /// + /// Before the message is send a couple of things are checked. If there is no identifier available, + /// the local identifier will be increased by one and set as the message identifier. + /// Second, if the acknowledgement identifier is not set it will be set to a random value. After this + /// the method will check for the total length of the message. If the total length is too large, + /// the message will be splitted into multiple messages. The maximum size for p2p messages over a + /// switchboard is 1202 bytes. The maximum size for p2p messages over a direct connection is 1352 + /// bytes. As a result the length of the splitted messages will be 1202 or 1352 bytes or smaller, + /// depending on the availability of a direct connection. + /// + /// If a direct connection is available the message is wrapped in a object + /// and send over the direct connection. Otherwise it will be send over a switchboard session. + /// If there is no switchboard session available, or it has become invalid, a new switchboard session + /// will be requested by asking this to the nameserver handler. Messages will be buffered until a + /// switchboard session, or a direct connection, becomes available. Upon a new connection the + /// buffered messages are directly send to the remote contact over the new connection. + /// + /// The P2PMessage to send to the remote contact. + public void SendMessage(NetworkMessage message) + { + P2PMessage p2pMessage = (P2PMessage)message; + + SetSequenceNumber(p2pMessage); + + if (Version == P2PVersion.P2PV1) + { + DeliverMessageV1(p2pMessage); + } + else if (Version == P2PVersion.P2PV2) + { + DeliverMessageV2(p2pMessage); + } + } + + #endregion + + #region IMessageHandler Members + + private IMessageProcessor messageProcessor = null; + + /// + /// The message processor that sends the P2P messages to the remote contact. + /// + public IMessageProcessor MessageProcessor + { + get + { + return messageProcessor; + } + set + { + messageProcessor = value; + + if (messageProcessor != null && + messageProcessor.GetType() != typeof(NSMessageProcessor)) + { + ValidateProcessor(); + SendBuffer(); + } + } + } + + /// + /// Handles P2PMessages. Other messages are ignored. + /// All incoming messages are supposed to belong to this session. + /// + public void HandleMessage(IMessageProcessor sender, NetworkMessage message) + { + P2PMessage p2pMessage = message as P2PMessage; + + Debug.Assert(p2pMessage != null, "Incoming message is not a P2PMessage", GetType().Name); + + if (p2pMessage.Version == P2PVersion.P2PV1) + { + // Keep track of the remote identifier + RemoteIdentifier = p2pMessage.Header.Identifier; + + if (p2pMessage.V1Header.Flags == P2PFlag.Error) + { + P2PTransferSession session = GetTransferSession(p2pMessage.Header.SessionId); + if (session != null) + { + session.AbortTransfer(); + } + return; + } + + // Check if it is a content message + if (p2pMessage.Header.SessionId > 0) + { + // Get the session to handle this message + P2PTransferSession session = GetTransferSession(p2pMessage.Header.SessionId); + + if (session != null) + session.HandleMessage(this, p2pMessage); + + return; + } + } + else if (p2pMessage.Version == P2PVersion.P2PV2) + { + // Keep track of the remote identifier + RemoteIdentifier = p2pMessage.Header.Identifier + p2pMessage.Header.MessageSize; + + // Check if it is a content message + if (p2pMessage.InnerBody != null && p2pMessage.Header.SessionId > 0) + { + // Get the session to handle this message + P2PTransferSession session = GetTransferSession(p2pMessage.Header.SessionId); + + if (session != null) + session.HandleMessage(this, p2pMessage); + + return; + } + } + + // It is not a datamessage. Extract the messages one-by-one and dispatch + // it to all handlers. Usually the MSNSLP handler. + IMessageHandler[] cpHandlers = handlers.ToArray(); + foreach (IMessageHandler handler in cpHandlers) + handler.HandleMessage(this, p2pMessage); + } + + #endregion + + #region Get/Add/Remove TransferSession + + /// + /// Returns the transfer session associated with the specified session identifier. + /// + public P2PTransferSession GetTransferSession(uint sessionId) + { + return transferSessions.ContainsKey(sessionId) ? transferSessions[sessionId] : null; + } + + /// + /// Adds the specified transfer session to the collection and sets the transfer session's message + /// processor to be the message processor of the p2p message session. This is usally a SB message + /// processor. + /// + /// + public void AddTransferSession(P2PTransferSession session) + { + if (session != null) + { + session.MessageProcessor = this; + transferSessions.Add(session.TransferProperties.SessionId, session); + } + } + + /// + /// Removes the specified transfer session from the collection. + /// + public void RemoveTransferSession(P2PTransferSession session) + { + if (session != null) + { + session.MessageProcessor = null; + + lock (transferSessions) + transferSessions.Remove(session.TransferProperties.SessionId); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, session.GetType() + " with SessionId = " + + session.TransferProperties.SessionId + " has been removed\r\n" + "There is(are) " + + transferSessions.Count + " P2PTransferSession still in this " + GetType()); + } + } + + #endregion + + #region Correct/Increase LocalIdentifier + + /// + /// Corrects the local identifier with the specified correction. + /// + /// + public void CorrectLocalIdentifier(int correction) + { + if (correction < 0) + LocalIdentifier -= (uint)Math.Abs(correction); + else + LocalIdentifier += (uint)Math.Abs(correction); + } + + /// + /// The identifier of the local client, increases with each message send + /// + public void IncreaseLocalIdentifier() + { + localIdentifier++; + if (localIdentifier == localBaseIdentifier) + localIdentifier++; + } + + #endregion + + #region SelectEndPointID + + public Guid SelectEndPointID(Contact contact) + { + if (Version == P2PVersion.P2PV1) + return Guid.Empty; + + foreach (Guid epId in contact.EndPointData.Keys) + { + if (epId != Guid.Empty) + return epId; + } + + return Guid.Empty; + } + + #endregion + + #region Clean Up + + /// + /// Aborts all running transfer sessions. + /// + public virtual void AbortAllTransfers() + { + List transferSessions_copy = new List(transferSessions.Values); + foreach (P2PTransferSession session in transferSessions_copy) + { + session.AbortTransfer(); + } + } + + /// + /// Removes references to handlers and the messageprocessor. Also closes running transfer sessions + /// and pending processors establishing connections. + /// + public virtual void CleanUp() + { + NSMessageHandler.ContactOffline -= (NSMessageHandler_ContactOffline); + OnSessionClosed(this); + NSMessageHandler.P2PHandler.OnSessionClosed(this); + + StopAllPendingProcessors(); + AbortAllTransfers(); + + lock (handlers) + handlers.Clear(); + + MessageProcessor = null; + + lock (transferSessions) + transferSessions.Clear(); + } + + /// + /// Cleans up p2p resources associated with the offline contact. + /// + private void NSMessageHandler_ContactOffline(object sender, ContactEventArgs e) + { + if (e.Contact.IsSibling(RemoteContact)) + { + CleanUp(); + } + } + + #endregion + + #region Protected Methods + + #region Event Handlers + + /// + /// Sets the processor as valid. + /// + protected virtual void ValidateProcessor() + { + processorValid = true; + } + + /// + /// Sets the processor as invalid, and requests the p2phandler for a new request. + /// + protected virtual void InvalidateProcessor() + { + if (ProcessorValid) + { + processorValid = false; + OnProcessorInvalid(); + } + } + + /// + /// Fires the ProcessorInvalid event. + /// + protected virtual void OnProcessorInvalid() + { + if (ProcessorInvalid != null) + ProcessorInvalid(this, EventArgs.Empty); + } + + /// + /// Fires the SessionClosed event. + /// + /// + protected virtual void OnSessionClosed(P2PMessageSession session) + { + if (SessionClosed != null) + SessionClosed(this, new P2PSessionAffectedEventArgs(session)); + } + + #endregion + + #region Wrap Message + + /// + /// Wraps a P2PMessage in a MSGMessage and SBMessage. + /// + /// + protected P2PMimeMessage WrapToMimeMessage(NetworkMessage networkMessage) + { + return new P2PMimeMessage(RemoteContactEPIDString, LocalContactEPIDString, networkMessage); + } + + /// + /// Wrap the message to a P2P direct connection message or a switchboard message base on the transfer bridge. + /// + /// The message to wrap. + /// + protected virtual NetworkMessage WrapToProcessorMessage(NetworkMessage message) + { + if (MessageProcessor is P2PDirectProcessor) + { + return new P2PDCMessage(message as P2PMessage); + } + + MimeMessage mimeMessage = WrapToMimeMessage(message); + SBMessage sbMessage = new SBMessage(); + sbMessage.Acknowledgement = "D"; + + sbMessage.InnerMessage = mimeMessage; + return sbMessage; + } + + #endregion + + #region SendBuffer / BufferMessage / TrySend + + /// + /// Try to resend any messages that were stored in the buffer. + /// + protected virtual void SendBuffer() + { + if (MessageProcessor == null) + return; + + try + { + while (sendMessages.Count > 0) + { + NetworkMessage p2pMessage = sendMessages.Dequeue(); + MessageProcessor.SendMessage(WrapToProcessorMessage(p2pMessage)); + } + } + catch (System.Net.Sockets.SocketException) + { + InvalidateProcessor(); + } + } + + /// + /// Buffer messages that can not be send because of an invalid message processor. + /// + /// + protected virtual void BufferMessage(NetworkMessage message) + { + if (sendMessages.Count >= 100) + System.Threading.Thread.CurrentThread.Join(200); + + sendMessages.Enqueue(message); + } + + /// + /// Buffer the message, then trigger event. + /// + /// + protected virtual void RequestProcessorAndBufferMessage(NetworkMessage message) + { + BufferMessage(message); + InvalidateProcessor(); + } + + /// + /// Add the message to send queue and send all messages in the queue. + /// + /// + protected virtual void EnqueueAndSendMessage(NetworkMessage message) + { + BufferMessage(message); + SendBuffer(); + } + + /// + /// Try to deliver the message to network. + /// + /// + /// + protected virtual bool TrySend(P2PMessage message) + { + try + { + if (MessageProcessor != null && + ((SocketMessageProcessor)MessageProcessor).Connected) + { + EnqueueAndSendMessage(message); + return true; + } + else + { + RequestProcessorAndBufferMessage(message); + } + } + catch (SocketException) + { + RequestProcessorAndBufferMessage(message); + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Invalid message processor detected, message buffered."); + return false; + } + + #endregion + + #endregion + + #region Private methods + + private bool CheckTransferLayerVersion(P2PVersion dstVersion) + { + if (Version != dstVersion) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, + "A wrong tranfer layer used, can't deliver a " + dstVersion.ToString() + " message via " + + Version.ToString() + " transfer layer."); + + return false; + } + + return true; + } + + private bool CheckTransferLayerVersion(P2PMessage dstMessage) + { + if (Version != dstMessage.Version) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, + "A wrong tranfer layer used, can't deliver a " + dstMessage.Version.ToString() + " message via " + + Version.ToString() + " transfer layer."); + + return false; + } + + return true; + } + + + private void DeliverMessageV1(P2PMessage p2pMessage) + { + if (!(CheckTransferLayerVersion(P2PVersion.P2PV1) && CheckTransferLayerVersion(p2pMessage))) + return; + + // check whether we have a direct connection (send p2pdc messages) or not (send sb messages) + int maxSize = DirectConnected ? 1352 : 1202; + + // split up large messages which go to the SB + if (Version == P2PVersion.P2PV1) + { + if (p2pMessage.Header.MessageSize > maxSize) + { + P2PMessage[] messages = p2pMessage.SplitMessage(maxSize); + foreach (P2PMessage chunkMessage in messages) + { + // now send it to propbably a SB processor + TrySend(chunkMessage); + } + } + else + { + TrySend(p2pMessage); + } + } + } + + private void DeliverMessageV2(P2PMessage p2pMessage) + { + if (!(CheckTransferLayerVersion(P2PVersion.P2PV2) && CheckTransferLayerVersion(p2pMessage))) + return; + + int maxSize = DirectConnected ? 1352 : 1202; + if (p2pMessage.V2Header.MessageSize - p2pMessage.V2Header.DataPacketHeaderLength > maxSize) + { + CorrectLocalIdentifier(-(int)p2pMessage.V2Header.MessageSize); + + P2PMessage[] messages = p2pMessage.SplitMessage(maxSize); + + foreach (P2PMessage chunkMessage in messages) + { + //chunkMessage.V2Header.Identifier = LocalIdentifier; + LocalIdentifier = chunkMessage.V2Header.Identifier + chunkMessage.V2Header.MessageSize; + // CorrectLocalIdentifier((int)chunkMessage.V2Header.MessageSize); + + // now send it to propbably a SB processor + TrySend(chunkMessage); + } + } + else + { + TrySend(p2pMessage); + } + } + + + private void SetSequenceNumber(P2PMessage p2pMessage) + { + // Check whether the sequence number is already set. This is important to check for acknowledge messages. + if (p2pMessage.Header.Identifier == 0) + { + if (Version == P2PVersion.P2PV1) + { + IncreaseLocalIdentifier(); + p2pMessage.Header.Identifier = LocalIdentifier; + } + else if (Version == P2PVersion.P2PV2) + { + p2pMessage.V2Header.Identifier = LocalIdentifier; + CorrectLocalIdentifier((int)p2pMessage.V2Header.MessageSize); + } + } + + if (Version == P2PVersion.P2PV1 && p2pMessage.V1Header.AckSessionId == 0) + { + p2pMessage.V1Header.AckSessionId = (uint)new Random().Next(50000, int.MaxValue); + } + } + + #endregion + } +}; diff --git a/MSNPSharp/DataTransfer/P2PTransferSession.cs b/MSNPSharp/DataTransfer/P2PTransferSession.cs new file mode 100644 index 0000000..f80fa85 --- /dev/null +++ b/MSNPSharp/DataTransfer/P2PTransferSession.cs @@ -0,0 +1,1263 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Net; +using System.IO; +using System.Threading; +using System.Collections; +using System.Diagnostics; +using System.Net.Sockets; +using System.Collections.Generic; + +namespace MSNPSharp.DataTransfer +{ + using MSNPSharp; + using MSNPSharp.Core; + + #region P2PTransferProgressedEventArgs + + [Serializable] + public class P2PTransferProgressedEventArgs : EventArgs + { + private ulong _transferred = 0; + private ulong _totalSize = 0; + private int _percent = 0; + + public P2PTransferProgressedEventArgs(ulong transferred, ulong totalSize) + { + if (totalSize == 0) + { + _percent = 100; + } + else + { + this._transferred = transferred; + this._totalSize = totalSize; + this._percent = (int)(((double)transferred / (double)totalSize) * 100); + } + } + + public ulong Transferred + { + get + { + return _transferred; + } + } + + public ulong TotalSize + { + get + { + return _totalSize; + } + } + + public int Percent + { + get + { + return _percent; + } + } + } + + #endregion + + /// + /// A single transfer of data within a p2p session. This is the Data Packet Layer of MSNP2P protocol. + /// + /// + /// P2PTransferSession handles all messages with a specified session id in the p2p header. Optional a + /// direct connection can be created. It will try to connect to the remote client or listening for + /// incoming connections. If that succeeds and the local client is the sender of the data a seperate + /// thread will be started to send data messages over the direct connection. However, if the direct + /// connection fails it will send the data messages over the switchboard session. These latter messages + /// go via the messenger servers and is therefore quite slow compared to direct connections but it is + /// guaranteed to work even when both machines are behind a proxy, firewall or router. + /// + public class P2PTransferSession : IMessageHandler, IMessageProcessor, IDisposable + { + #region Events + + /// + /// Occurs when the sending of data messages has started. + /// + public event EventHandler TransferStarted; + + /// + /// Occurs when the sending/receiving of data messages has arrived. + /// + public event EventHandler TransferProgressed; + + /// + /// Occurs when the sending of data messages has finished. + /// + public event EventHandler TransferFinished; + + /// + /// Occurs when the transfer of data messages has been aborted. + /// + public event EventHandler TransferAborted; + + #endregion + + #region Members + + private volatile int abortThread = 0; + private Thread transferThread = null; + private bool transferFinishedFired = false; + + private uint messageFlag = 0; + private uint messageFooter = 0; + private uint dataPreparationAck = 0; + private ushort dataPacketNumber = 0; + private uint dataMessageIdentifier = 0; + + private bool isSender = false; + private bool autoCloseStream = false; + private Stream dataStream = new MemoryStream(); + private object clientData = null; + + private P2PVersion version = P2PVersion.P2PV1; + private P2PMessageSession messageSession = null; + private MSNSLPTransferProperties transferProperties = null; + private bool waitingDirectConnection = false; + + #endregion + + #region Constructors & Destructors + + protected P2PTransferSession() + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Constructing p2p transfer session object", GetType().Name); + } + + public P2PTransferSession(P2PVersion ver, MSNSLPTransferProperties properties, P2PMessageSession transferLayer) + { + this.version = ver; + this.transferProperties = properties; + this.MessageSession = transferLayer; + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Constructing p2p transfer session object, version = " + ver.ToString(), GetType().Name); + } + + ~P2PTransferSession() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + // Dispose managed resources + if (dataStream != null) + dataStream.Dispose(); + + MessageSession.UnregisterHandler(this); + MessageSession.RemoveTransferSession(this); + } + + // Free native resources + } + + #endregion + + #region Properties + + /// + /// The message session which keeps track of the local / remote message identifiers and redirects + /// messages to this handler based on the session id. + /// + public P2PMessageSession MessageSession + { + get + { + return messageSession; + } + set + { + if (messageSession != null) + { + messageSession.RemoveTransferSession(this); + messageSession.DirectConnectionEstablished -= (messageSession_DirectConnectionEstablished); + messageSession.DirectConnectionFailed -= (messageSession_DirectConnectionFailed); + } + + messageSession = value; + + if (messageSession != null) + { + messageSession.AddTransferSession(this); //The massage processor of transfer session will be set by AddTransferSession. + messageSession.DirectConnectionEstablished += (messageSession_DirectConnectionEstablished); + messageSession.DirectConnectionFailed += (messageSession_DirectConnectionFailed); + } + } + } + + /// + /// The transfer properties for this transfer session. + /// + public MSNSLPTransferProperties TransferProperties + { + get + { + return transferProperties; + } + } + + /// + /// P2P version + /// + public P2PVersion Version + { + get + { + return version; + } + } + + + /// + /// Defines whether the local client is sender or receiver + /// + public bool IsSender + { + get + { + return isSender; + } + set + { + isSender = value; + } + } + + /// + /// Defines whether the stream is automatically closed after the transfer has finished or been aborted. + /// + public bool AutoCloseStream + { + get + { + return autoCloseStream; + } + set + { + autoCloseStream = value; + } + } + + /// + /// This property can be used by the client-programmer to include application specific data. + /// + public object ClientData + { + get + { + return clientData; + } + set + { + clientData = value; + } + } + + /// + /// The stream to read from when data is send, or to write to when data is received. + /// Default is a MemorySteam. + /// + /// + /// In the eventhandler, when an invitation is received, the client programmer must set this property + /// in order to enable the transfer to succeed. In the case of the filetransfer, when the local client + /// is the receiver, the incoming data is written to the specified datastream. In the case of the + /// invitation for a msn object (display picture, emoticons, background), when the local client is + /// the sender, the outgoing data is read from the specified datastream. + /// + public Stream DataStream + { + get + { + return dataStream; + } + set + { + dataStream = value; + } + } + + + /// + /// This value is set in the flag field in a p2p header. + /// + /// + /// For filetransfers this value is for example 0x1000030 + /// + public uint MessageFlag + { + get + { + return messageFlag; + } + set + { + messageFlag = value; + } + } + + /// + /// This value is set in the footer field in a p2p header. + /// + public uint MessageFooter + { + get + { + return messageFooter; + } + set + { + messageFooter = value; + } + } + + /// + /// Tracked to know when an acknowledgement for the (switchboards) data preparation message is received. + /// + internal uint DataPreparationAck + { + get + { + return dataPreparationAck; + } + set + { + dataPreparationAck = value; + } + } + + /// + /// The PackageNumber field used by p2pv2 messages. + /// + internal ushort DataPacketNumber + { + get + { + return dataPacketNumber; + } + + set + { + dataPacketNumber = value; + } + } + + /// + /// Indicates whether the session is waiting for the result of a direct connection attempt + /// + protected bool WaitingDirectConnection + { + get + { + return waitingDirectConnection; + } + set + { + waitingDirectConnection = value; + } + } + + /// + /// The thread in which the data messages are send + /// + protected Thread TransferThread + { + get + { + return transferThread; + } + set + { + transferThread = value; + } + } + + #endregion + + #region IMessageHandler Members + + private IMessageProcessor messageProcessor; + + /// + /// The message processor to which p2p messages (this includes p2p data messages) will be send + /// + public IMessageProcessor MessageProcessor + { + get + { + return messageProcessor; + } + set + { + if (value != null && object.ReferenceEquals(messageProcessor, value)) + return; + + if (value == null && messageProcessor == null) + return; + + if (value == null && messageProcessor != null) + { + messageProcessor.UnregisterHandler(this); + + messageProcessor = value; + return; + } + + if (messageProcessor != null) + { + messageProcessor.UnregisterHandler(this); + } + + messageProcessor = value; + messageProcessor.RegisterHandler(this); + } + } + + /// + /// Handles P2PMessages. Other messages are ignored. All incoming messages are supposed to belong to this session. + /// + public void HandleMessage(IMessageProcessor sender, NetworkMessage message) + { + P2PMessage p2pMessage = message as P2PMessage; + + Trace.Assert(p2pMessage != null, "Incoming message is not a P2PMessage", GetType().Name); + + if (p2pMessage.Header.SessionId != TransferProperties.SessionId) + { + //The data is not for this transfer session, return. + return; + } + + bool handled = WriteToDataStream(p2pMessage); + + if (handled) + return; + + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, + "P2P Info message received, session Id: " + TransferProperties.SessionId + "\r\n" + + p2pMessage.ToDebugString(), GetType().Name); + + // It is not a datamessage. Extract the messages one-by-one and dispatch it to all handlers. + IMessageHandler[] cpHandlers = handlers.ToArray(); + foreach (IMessageHandler handler in cpHandlers) + handler.HandleMessage(this, p2pMessage); + + } + + private bool WriteToDataStream(P2PMessage p2pMessage) + { + if (p2pMessage.Version == P2PVersion.P2PV1) + { + // Keep track of the remote identifier + MessageSession.RemoteIdentifier = p2pMessage.Header.Identifier; + + #region P2P Version 1 + if (p2pMessage.V1Header.Flags == P2PFlag.TlpError) + { + AbortTransfer(); + return true; + } + + // check to see if our session data has been transferred correctly + if (p2pMessage.Header.SessionId > 0 && + p2pMessage.Header.IsAcknowledgement && + p2pMessage.V1Header.AckSessionId == dataMessageIdentifier) + { + // inform the handlers + OnTransferFinished(); + return true; + } + + // check if it is a content message + // if it is not a file transfer message, and the footer is not set to the corresponding value, ignore it. + if (p2pMessage.InnerBody.Length > 0) + { + if ( + /* m$n 7.5 (MSNC5) >=, footer: dp=12,emo=11,file=2 */ + ((p2pMessage.V1Header.Flags & P2PFlag.Data) == P2PFlag.Data && p2pMessage.Footer == P2PConst.DisplayImageFooter12) || + (p2pMessage.V1Header.Flags == P2PFlag.FileData && p2pMessage.Footer == P2PConst.FileTransFooter2) || + ((p2pMessage.V1Header.Flags & P2PFlag.Data) == P2PFlag.Data && p2pMessage.Footer == (uint)P2PConst.CustomEmoticonFooter11) || + /* m$n 7.0 (MSNC4) <=, footer is 1 (dp and custom emoticon) */ + ((p2pMessage.V1Header.Flags & P2PFlag.Data) == P2PFlag.Data || p2pMessage.Footer == 1) + ) + { + // indicates whether we must stream this message + bool writeToStream = true; + + // check if it is a data preparation message send via the SB + if (p2pMessage.Header.TotalSize == 4 && + p2pMessage.Header.MessageSize == 4 + && BitConverter.ToInt32(p2pMessage.InnerBody, 0) == 0) + { + writeToStream = false; + } + + if (writeToStream) + { + // store the data message identifier because we want to reference it if we abort the transfer + dataMessageIdentifier = p2pMessage.Header.Identifier; + + if (DataStream == null) + throw new MSNPSharpException("Data was received in a P2P session, but no datastream has been specified to write to."); + + if (DataStream.CanWrite) + { + if (DataStream.Length < (long)p2pMessage.V1Header.Offset + (long)p2pMessage.InnerBody.Length) + DataStream.SetLength((long)p2pMessage.V1Header.Offset + (long)p2pMessage.InnerBody.Length); + + DataStream.Seek((long)p2pMessage.V1Header.Offset, SeekOrigin.Begin); + DataStream.Write(p2pMessage.InnerBody, 0, p2pMessage.InnerBody.Length); + + try + { + OnTransferProgressed(new P2PTransferProgressedEventArgs( + (p2pMessage.V1Header.Offset + p2pMessage.Header.MessageSize), p2pMessage.Header.TotalSize)); + } + catch (Exception xferExc) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "Error occured when fired TransferProgressed: " + xferExc.ToString(), GetType().Name); + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "Data received, " + (p2pMessage.V1Header.Offset + (ulong)p2pMessage.Header.MessageSize).ToString() + + " of " + p2pMessage.Header.TotalSize); + } + // check for end of file transfer + if (p2pMessage.V1Header.Offset + p2pMessage.Header.MessageSize == p2pMessage.Header.TotalSize) + { + // Close data stream before sending ack + if (AutoCloseStream) + DataStream.Close(); + + P2PMessage ack = p2pMessage.CreateAcknowledgement(); + try + { + ack.Header.SessionId = p2pMessage.Header.SessionId; + SendMessage(ack); + } + catch (Exception) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, + "ACK couldn't be sent, closed remotely after last packet? The ACK was: " + ack.ToDebugString(), GetType().Name); + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "All data for transfer session " + TransferProperties.SessionId + + " have been received, trigger OnTransferFinished event."); + + OnTransferFinished(); + } + } + // finished handling this message + return true; + } + } + #endregion + } + + if (p2pMessage.Version == P2PVersion.P2PV2) + { + // Keep track of the remote identifier + MessageSession.RemoteIdentifier = p2pMessage.Header.Identifier + p2pMessage.Header.MessageSize; + + #region P2P Version 2 + + if (p2pMessage.InnerBody.Length == 4 && + p2pMessage.V2Header.TFCombination == TFCombination.First && + BitConverter.ToInt32(p2pMessage.InnerBody, 0) == 0) + { + //Data preperation message. + return true; + } + + // check if it is a content message + // if it is not a file transfer message, and the footer is not set to the corresponding value, ignore it. + if (p2pMessage.V2Header.MessageSize > 0) + { + if (p2pMessage.V2Header.TFCombination == (TFCombination.MsnObject) || + p2pMessage.V2Header.TFCombination == (TFCombination.MsnObject | TFCombination.First) || + p2pMessage.V2Header.TFCombination == (TFCombination.FileTransfer) || + p2pMessage.V2Header.TFCombination == (TFCombination.FileTransfer | TFCombination.First)) + { + // store the data message identifier because we want to reference it if we abort the transfer + DataPacketNumber = p2pMessage.V2Header.PackageNumber; + + if (DataStream == null) + throw new MSNPSharpException("Data was received in a P2P session, but no datastream has been specified to write to."); + + if (DataStream.CanWrite) + { + DataStream.Seek(0, SeekOrigin.End); + DataStream.Write(p2pMessage.InnerBody, 0, p2pMessage.InnerBody.Length); + + try + { + OnTransferProgressed(new P2PTransferProgressedEventArgs( + (ulong)DataStream.Position, (ulong)DataStream.Position + p2pMessage.V2Header.DataRemaining)); + } + catch (Exception xferExc) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "Error occured when fired TransferProgressed: " + xferExc.ToString(), GetType().Name); + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "Data received, " + (ulong)DataStream.Position + + " of " + ((ulong)DataStream.Position + p2pMessage.V2Header.DataRemaining)); + + + } + // check for end of file transfer + if (p2pMessage.V2Header.DataRemaining == 0) + { + if (AutoCloseStream) + DataStream.Close(); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "All data for transfer session " + TransferProperties.SessionId + + " have been received, trigger OnTransferFinished event."); + + OnTransferFinished(); + } + // finished handling this message + return true; + + } + } + + #endregion + } + + return false; + } + + + #endregion + + #region IMessageProcessor Members + + private List handlers = new List(); + + /// + /// Registers handlers for incoming p2p messages. + /// + /// + public void RegisterHandler(IMessageHandler handler) + { + if (handler != null && !handlers.Contains(handler)) + { + lock (handlers) + { + handlers.Add(handler); + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, + handler.ToString() + " added to handler list.", GetType().Name); + } + } + } + + /// + /// Unregisters handlers. + /// + /// + public void UnregisterHandler(IMessageHandler handler) + { + if (handler != null) + { + lock (handlers) + { + while (handlers.Remove(handler)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, + handler.ToString() + " removed from handler list.", GetType().Name); + } + } + } + } + + /// + /// Sends a message for this session to the message processor. If a direct connection is established, + /// the p2p message is directly send to the message processor. If there is no direct connection + /// available, it will wrap the incoming p2p message in a MSGMessage with the correct parameters. + /// It also sets the identifiers and acknowledge session, provided they're not already set. + /// + /// + public void SendMessage(NetworkMessage message) + { + P2PMessage p2pMsg = message as P2PMessage; + if (p2pMsg != null) + { + SendMessage(p2pMsg); + return; + } + + SLPMessage slpMsg = message as SLPMessage; + if (slpMsg != null) + { + SendMessage(slpMsg); + return; + } + + throw new InvalidDataException("Can not send " + message.GetType().ToString() + " via P2P Transfer session."); + } + + #endregion + + #region StartDataTransfer / AbortTransfer + + /// + /// Starts a seperate thread to send the data in the stream to the remote client. It will first wait + /// for a direct connection if tryDirectConnection is set to true. + /// + /// This method will not open or close the specified datastream. + public void StartDataTransfer(bool tryDirectConnection) + { + if (transferThread != null) + { + throw new MSNPSharpException("Start of data transfer failed because there is already a thread sending the data."); + } + + Debug.Assert(TransferProperties.SessionId != 0, "Trying to initiate p2p data transfer but no session is specified"); + Debug.Assert(dataStream != null, "Trying to initiate p2p data transfer but no session is specified"); + + isSender = true; + + if (messageSession.DirectConnected == false && + messageSession.DirectConnectionAttempt == false && + tryDirectConnection == true) + { + waitingDirectConnection = true; + return; + } + + waitingDirectConnection = false; + + transferThread = new Thread(new ParameterizedThreadStart(TransferDataEntry)); + transferThread.Start(this); + } + + /// + /// Aborts the datatransfer, if available. This will send a P2P abort message and stop the sending + /// thread. It will not close a direct connection. If AutoCloseStream is set to true, the datastream + /// will be closed. + /// + /// This function is called by internal. + /// If you want to abort the current transfer, call + /// + /// + public void AbortTransfer() + { + if (transferThread != null) + { + if (transferThread.IsAlive) + { + Thread.BeginCriticalRegion(); + abortThread = 1; //transferThread.Abort(); + Thread.EndCriticalRegion(); + } + transferThread = null; + OnTransferAborted(); + } + + MessageSession.RemoveTransferSession(this); + + if (AutoCloseStream) + DataStream.Close(); + } + + #endregion + + #region GetNextSLP ID + + /// + /// Get the next data package number for the SIP request text message, such as INVITE and BYE. + /// + /// + public static ushort GetNextSLPRequestDataPacketNumber(ushort baseDataPacketNumber) + { + if (baseDataPacketNumber < ushort.MaxValue) + return ++baseDataPacketNumber; + + return baseDataPacketNumber; + } + + /// + /// Get the next data package number to the SIP status text message, such as 200 OK and 603 Decline. + /// + /// + public static ushort GetNextSLPStatusDataPacketNumber(ushort baseDataPacketNumber) + { + if (baseDataPacketNumber > 0) + return --baseDataPacketNumber; + + return baseDataPacketNumber; + } + + /// + /// Get the next data package number for the SIP request text message, such as INVITE and BYE. + /// + /// + public ushort GetNextSLPRequestDataPacketNumber() + { + if (dataPacketNumber < ushort.MaxValue) + return ++dataPacketNumber; + + return dataPacketNumber; + } + + /// + /// Get the next data package number to the SIP status text message, such as 200 OK and 603 Decline. + /// + /// + public ushort GetNextSLPStatusDataPacketNumber() + { + if (dataPacketNumber > 0) + return --dataPacketNumber; + + return dataPacketNumber; + } + + #endregion + + #region SendMessage / Wrap Message / DeliverToTransferLayer + + + + public P2PMessage SendMessage(P2PMessage p2pMessage) + { + DeliverToTransferLayer(p2pMessage); + return p2pMessage; + } + + public P2PMessage SendMessage(SLPMessage slpMessage) + { + if (slpMessage is SLPRequestMessage) + { + if ((slpMessage as SLPRequestMessage).Method == MSNSLPRequestMethod.BYE) + TransferProperties.SessionCloseState--; + } + return SendMessage(WrapSLPMessage(slpMessage)); + } + + private P2PMessage WrapSLPMessage(SLPMessage slpMessage) + { + P2PMessage p2pMessage = new P2PMessage(Version); + p2pMessage.InnerMessage = slpMessage; + + if (Version == P2PVersion.P2PV2) + { + p2pMessage.V2Header.TFCombination = TFCombination.First; + + if (slpMessage is SLPRequestMessage) + { + p2pMessage.V2Header.PackageNumber = GetNextSLPRequestDataPacketNumber(); + } + else if (slpMessage is SLPStatusMessage) + { + p2pMessage.V2Header.PackageNumber = GetNextSLPStatusDataPacketNumber(); + } + } + + if (Version == P2PVersion.P2PV1) + { + p2pMessage.V1Header.Flags = P2PFlag.MSNSLPInfo; + } + + return p2pMessage; + } + + private bool DeliverToTransferLayer(P2PMessage p2pMessage) + { + if (TransferProperties != null) + { + if (p2pMessage.IsSLPData) + { + p2pMessage.Header.SessionId = 0; + } + else + { + p2pMessage.Header.SessionId = TransferProperties.SessionId; + } + } + else + { + p2pMessage.Header.SessionId = 0; + } + + if (MessageSession != null) + { + if (!MessageSession.DirectConnected) + { + p2pMessage.PrepareMessage(); + } + + MessageSession.SendMessage(p2pMessage); + return true; + } + + return false; + } + + #endregion + + #region Event Handlers + + /// + /// Fires the TransferStarted event. + /// + protected virtual void OnTransferStarted() + { + if (TransferStarted != null) + TransferStarted(this, EventArgs.Empty); + } + + protected virtual void OnTransferProgressed(P2PTransferProgressedEventArgs e) + { + if (TransferProgressed != null) + TransferProgressed(this, e); + } + + /// + /// Fires the TransferFinished event. + /// + protected virtual void OnTransferFinished() + { + if (TransferFinished != null) + { + if (!transferFinishedFired) + { + transferFinishedFired = true; + TransferFinished(this, EventArgs.Empty); + } + } + } + + /// + /// Fires the TransferAborted event. + /// + protected virtual void OnTransferAborted() + { + if (TransferAborted != null) + TransferAborted(this, EventArgs.Empty); + } + + /// + /// Start the transfer session if it is waiting for a direct connection. + /// + /// + /// + private void messageSession_DirectConnectionEstablished(object sender, EventArgs e) + { + if (waitingDirectConnection) + { + waitingDirectConnection = false; + StartDataTransfer(true); + } + } + + /// + /// Start the transfer session if it is waiting for a direct connection. Because the direct + /// connection attempt failed the transfer will be over the switchboard. + /// + private void messageSession_DirectConnectionFailed(object sender, EventArgs e) + { + if (waitingDirectConnection) + { + waitingDirectConnection = false; + StartDataTransfer(false); + } + } + + #endregion + + #region TransferDataEntry & AbortTransferThread + + /// + /// Entry point for the thread. This thread will send the data messages to the message processor. + /// In case it is a direct connection P2PDCMessages will be send. If no direct connection is + /// established P2PMessage objects are wrapped in a SBMessage object and send to the message + /// processor. Which is in the latter case probably a SB processor. + /// + protected void TransferDataEntry(object thisObject) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Starting transfer thread...", GetType().Name); + + OnTransferStarted(); + + bool wasLastPacket = false; + uint sessId = TransferProperties.SessionId; + + try + { + bool direct = MessageSession.DirectConnected; + + #region data preparation message for SB + + // Send the data preparation (4 x 0x00) message + // This is a MUST for all the MSNObject transfer (DisplayImage, CustomEmoticon.. etc) + if (direct == false && + (TransferProperties.DataType == DataTransferType.DisplayImage || + TransferProperties.DataType == DataTransferType.Emoticon)) + { + P2PDataMessage p2pDataMessage = new P2PDataMessage(Version); + p2pDataMessage.WritePreparationBytes(); + p2pDataMessage.Header.SessionId = sessId; + + if (Version == P2PVersion.P2PV1) + { + MessageSession.IncreaseLocalIdentifier(); + p2pDataMessage.Header.Identifier = MessageSession.LocalIdentifier; + + p2pDataMessage.V1Header.AckSessionId = DataPreparationAck; + p2pDataMessage.Footer = MessageFooter; + } + + if (Version == P2PVersion.P2PV2) + { + p2pDataMessage.V2Header.TFCombination = TFCombination.First; + } + + SendMessage(p2pDataMessage); + } + + #endregion + + if (Version == P2PVersion.P2PV1) + { + MessageSession.IncreaseLocalIdentifier(); + } + + uint messageIdentifier = MessageSession.LocalIdentifier; + + // Tracked to send the disconnecting message (0x40 flag) with the correct datamessage identifiers as + // it's acknowledge identifier. (protocol) + dataMessageIdentifier = messageIdentifier; + + long currentPosition = 0; + long lastPosition = dataStream.Length; + uint currentACK = (DataPreparationAck > 0) ? DataPreparationAck : (uint)new Random().Next(50000, int.MaxValue); + + int rakCounter = 128; + TFCombination tfComb = TFCombination.First; + if (MessageFlag == (uint)P2PFlag.MSNObjectData) + { + tfComb |= TFCombination.MsnObject; + } + else if (MessageFlag == (uint)P2PFlag.FileData) + { + tfComb |= TFCombination.FileTransfer; + } + + while (currentPosition < lastPosition && (0 == abortThread)) + { + P2PDataMessage p2pDataMessage = new P2PDataMessage(Version); + p2pDataMessage.Header.SessionId = sessId; + + #region setup packet + + if (Version == P2PVersion.P2PV1) + { + p2pDataMessage.V1Header.Offset = (ulong)currentPosition; + p2pDataMessage.V1Header.TotalSize = (ulong)dataStream.Length; + p2pDataMessage.V1Header.Flags = (P2PFlag)MessageFlag; + p2pDataMessage.Header.Identifier = messageIdentifier; + p2pDataMessage.V1Header.AckSessionId = currentACK; + p2pDataMessage.Footer = MessageFooter; + + if (currentACK < uint.MaxValue) + { + currentACK++; + } + else + { + currentACK--; + } + } + else if (Version == P2PVersion.P2PV2) + { + if (--rakCounter < 0) + { + p2pDataMessage.V2Header.OperationCode = (byte)OperationCode.RAK; + rakCounter = 128; + } + + // Always sets to 1. + p2pDataMessage.V2Header.PackageNumber = 1; + p2pDataMessage.V2Header.TFCombination = tfComb; + + if (currentPosition == 0) + { + tfComb &= ~TFCombination.First; + } + } + + lock (dataStream) + { + // Write bytes to inner body. + // DataRemaining & MessageSize will be calculated automatically for p2pv2. + dataStream.Seek(currentPosition, SeekOrigin.Begin); + currentPosition += p2pDataMessage.WriteBytes(dataStream, 1202); + + if (currentPosition == lastPosition) + { + wasLastPacket = true; + } + } + + #endregion + + System.Threading.Thread.CurrentThread.Join(300); + + SendMessage(p2pDataMessage); + + try + { + OnTransferProgressed(new P2PTransferProgressedEventArgs((ulong)currentPosition, (ulong)lastPosition)); + } + catch (Exception xferExc) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "Error occured when fired TransferProgressed: " + xferExc.ToString(), GetType().Name); + } + + } + + } + catch (SocketException sex) + { + if (sex.ErrorCode == 10053) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "You've closed a connection: " + sex.ToString(), GetType().Name); + } + + abortThread = 1; + OnTransferAborted(); + } + catch (ObjectDisposedException oex) + { + abortThread = 1; + MessageSession.CloseDirectConnection(); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Exception in transfer thread: " + oex.ToString(), GetType().Name); + } + finally + { + if (wasLastPacket && (0 == abortThread)) + { + OnTransferFinished(); + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, + "Stopping transfer thread (" + Thread.CurrentThread.ManagedThreadId + ") for session " + sessId + "... Aborted: " + (abortThread == 1), GetType().Name); + } + } + + + + #endregion + + #region AcceptInvitation / SendAbortMessage / SendDisconnectMessage / AbortTransferThread + + /// + /// Send the MSNSLP 200 OK message and start data transfer. + /// + /// + internal void AcceptInvitation(SLPStatusMessage acceptanceMessage) + { + P2PMessage replyMessage = SendMessage(acceptanceMessage); + + if (Version == P2PVersion.P2PV1) + { + DataPreparationAck = replyMessage.V1Header.AckSessionId; + } + + if (IsSender) + StartDataTransfer(false); + } + + /// + /// Sends the remote client a p2p message with the 0x80 flag to abort. + /// + private void SendAbortMessage(SLPRequestMessage closingMessage) + { + if (Version == P2PVersion.P2PV2) //In p2pv2, just send a MSNSLP BYE instead. + { + SendMessage(closingMessage); + } + + if (Version == P2PVersion.P2PV1) + { + P2PMessage disconnectMessage = new P2PMessage(P2PVersion.P2PV1); + disconnectMessage.V1Header.Flags = P2PFlag.TlpError; + disconnectMessage.V1Header.SessionId = TransferProperties.SessionId; + disconnectMessage.V1Header.AckSessionId = dataMessageIdentifier; + SendMessage(disconnectMessage); + } + } + + /// + /// Sends the remote client a p2p message with the 0x40 flag to indicate we are going to close the connection. + /// + internal void SendDisconnectMessage(SLPRequestMessage closingMessage) + { + if (Version == P2PVersion.P2PV2) //In p2pv2, just send a MSNSLP BYE instead. + { + SendMessage(closingMessage); + } + + if (Version == P2PVersion.P2PV1) + { + P2PMessage disconnectMessage = new P2PMessage(P2PVersion.P2PV1); + disconnectMessage.V1Header.Flags = P2PFlag.CloseSession; + disconnectMessage.Header.SessionId = TransferProperties.SessionId; + disconnectMessage.V1Header.AckSessionId = dataMessageIdentifier; // aargh it took me long to figure this one out + SendMessage(disconnectMessage); + } + } + + #endregion + } +}; diff --git a/MSNPSharp/DisplayImage.cs b/MSNPSharp/DisplayImage.cs new file mode 100644 index 0000000..1ca826c --- /dev/null +++ b/MSNPSharp/DisplayImage.cs @@ -0,0 +1,185 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + [Serializable()] + public class DisplayImage : MSNObject + { + private Image image = null; + private bool isDefaultImage = false; + private const string defaultLocation = "MSNPSharpDefault"; + + public static Image DefaultImage + { + get + { + return Properties.Resources.WLXLarge_default; + } + } + + public bool IsDefaultImage + { + get + { + return isDefaultImage; + } + + internal set + { + isDefaultImage = value; + } + } + + public DisplayImage() + : this(string.Empty, false) + { + } + + public DisplayImage(string creator) + : this(creator, false) + { + } + + internal DisplayImage(string creator, bool isDefault) + { + ObjectType = MSNObjectType.UserDisplay; + + if (isDefault) + { + Location = defaultLocation; + // There is no need to create a stream for the default image. + //PersistentStream stream = new PersistentStream(new MemoryStream()); + //(defaultImage.Clone() as Image).Save(stream, defaultImage.RawFormat); + //DataStream = stream; + } + + isDefaultImage = isDefault; + Creator = creator; + + RetrieveImage(); + } + + public DisplayImage(string creator, MemoryStream input, string location) + : base(creator, new MemoryStream(input.ToArray()), MSNObjectType.UserDisplay, location) + { + RetrieveImage(); + } + + public DisplayImage(string creator, MemoryStream input) + : this(creator, input, defaultLocation) + { + } + + public static DisplayImage CreateDefaultImage(string creator) + { + return new DisplayImage(creator, true); + } + + public Image Image + { + get + { + lock (SyncObject) + { + if (DataStream != null) + RetrieveImage(); + + return image == null ? null : image.Clone() as Image; + } + } + } + + public void RetrieveImage() + { + UpdateStream(); + + Stream input = DataStream; + + if (input != null) + { + lock (input) + { + input.Position = 0; + if (input.Length > 0) + { + lock (SyncObject) + image = System.Drawing.Image.FromStream(input); + } + + input.Position = 0; + } + } + } + + /// + /// Get the raw stream data for saving. + /// + /// + internal byte[] GetRawData() + { + if (IsDefaultImage) + return null; + + if (DataStream == null) + return null; + + if (OpenStream().CanRead) + { + byte[] data = new byte[Size]; + DataStream.Seek(0, SeekOrigin.Begin); + DataStream.Read(data, 0, Size); + DataStream.Close(); + return data; + } + + DataStream.Close(); + return null; + } + + protected override bool ContextEqual(string contextPlain) + { + if (IsDefaultImage && string.IsNullOrEmpty(contextPlain)) + return true; + + return base.ContextEqual(contextPlain); + } + } +}; diff --git a/MSNPSharp/Emoticon.cs b/MSNPSharp/Emoticon.cs new file mode 100644 index 0000000..817f5d1 --- /dev/null +++ b/MSNPSharp/Emoticon.cs @@ -0,0 +1,81 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + [Serializable()] + public class Emoticon : DisplayImage + { + string shortcut; + + public Emoticon() + { + ObjectType = MSNObjectType.Emoticon; + Location = Guid.NewGuid().ToString(); + } + + public Emoticon(string creator, string shortcut) + { + ObjectType = MSNObjectType.Emoticon; + Location = Guid.NewGuid().ToString(); + Creator = creator; + Shortcut = shortcut; + } + + public Emoticon(string creator, MemoryStream input, string location, string shortcut) + : base(creator, input, location) + { + ObjectType = MSNObjectType.Emoticon; + Shortcut = shortcut; + } + + /// + /// The string that will be replaced by the emoticons. + /// + public string Shortcut + { + get + { + return shortcut; + } + set + { + shortcut = value; + } + } + } +}; \ No newline at end of file diff --git a/MSNPSharp/EmoticonMessage.cs b/MSNPSharp/EmoticonMessage.cs new file mode 100644 index 0000000..52c30cf --- /dev/null +++ b/MSNPSharp/EmoticonMessage.cs @@ -0,0 +1,159 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Text; +using System.Collections; +using System.Collections.Generic; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + /// + /// A message that defines a list of emoticons used in the next textmessage. + /// + [Serializable()] + public class EmoticonMessage : NetworkMessage + { + private EmoticonType emoticontype = EmoticonType.StaticEmoticon; + /// + /// Constructor. + /// + public EmoticonMessage() + { + emoticons = new List(); + } + + /// + /// Constructor with a single emoticon supplied. + /// + /// + /// + public EmoticonMessage(Emoticon emoticon, EmoticonType type) + { + if (null == emoticon) + throw new ArgumentNullException("emoticon"); + + emoticons = new List(); + emoticons.Add(emoticon); + emoticontype = type; + } + + /// + /// Type of emoticons. + /// + public EmoticonType EmoticonType + { + get { return emoticontype; } + } + + /// + /// Constructor with multiple emoticons supplied. + /// + /// + /// + public EmoticonMessage(List emoticons, EmoticonType type) + { + Emoticons = new List(emoticons); + emoticontype = type; + } + + /// + /// + private List emoticons; + + /// + /// The emoticon that is defined in this message + /// + public List Emoticons + { + get + { + return emoticons; + } + set + { + emoticons = value; + } + } + + /// + /// Sets the Emoticon property. + /// + /// + public override void ParseBytes(byte[] data) + { + // set the text property for easy retrieval + string body = System.Text.Encoding.UTF8.GetString(data).Trim(); + + Emoticons = new List(); + + string[] values = body.Split('\t'); + + for (int i = 0; i < values.Length - 1; i += 2) + { + Emoticon emoticon = new Emoticon(); + emoticon.Shortcut = values[i].Trim(); + emoticon.SetContext(values[i + 1].Trim()); + + Emoticons.Add(emoticon); + } + } + + + /// + /// Gets the header with the body appended as a byte array + /// + /// + public override byte[] GetBytes() + { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < emoticons.Count; i++) + { + Emoticon emoticon = (Emoticon)emoticons[i]; + builder.Append(emoticon.Shortcut).Append('\t').Append(emoticon.ContextPlain).Append('\t'); + } + return System.Text.Encoding.UTF8.GetBytes(builder.ToString()); + } + + + /// + /// + /// + public override string ToString() + { + return System.Text.Encoding.UTF8.GetString(GetBytes()); + } + + } +}; diff --git a/MSNPSharp/EndPointData.cs b/MSNPSharp/EndPointData.cs new file mode 100644 index 0000000..501cf76 --- /dev/null +++ b/MSNPSharp/EndPointData.cs @@ -0,0 +1,257 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace MSNPSharp +{ + /// + /// Represent the information of a certain endpoint. + /// + [Serializable] + public class EndPointData + { + #region Fields and Properties + + private Guid id = Guid.Empty; + + /// + /// The Id of endpoint data. + /// + public Guid Id + { + get + { + return id; + } + } + + private ClientCapacities clientCapacities = ClientCapacities.None; + + /// + /// The capacities of the client at this enpoint. + /// + public ClientCapacities ClientCapacities + { + get + { + return clientCapacities; + } + + internal set + { + clientCapacities = value; + } + } + + private ClientCapacitiesEx clientCapacitiesEx = ClientCapacitiesEx.None; + + /// + /// The new capacities of the client at this enpoint. + /// + public ClientCapacitiesEx ClientCapacitiesEx + { + get + { + return clientCapacitiesEx; + } + internal set + { + clientCapacitiesEx = value; + } + } + + private string account = string.Empty; + + /// + /// The account of this endpoint, different endpoints might share the same account. + /// + public string Account + { + get + { + return account; + } + } + + #endregion + + protected EndPointData() + { + } + + /// + /// Constructor. + /// + /// + /// The endpoint Id. + public EndPointData(string account, Guid epId) + { + this.id = epId; + this.account = account.ToLowerInvariant(); + } + + /// + /// Constructor. + /// + /// The string represents the endpoint with the format [account];[EndPoingGUID] + public EndPointData(string uniqueEPIDString) + { + account = GetAccountFromUniqueEPIDString(uniqueEPIDString); + id = GetEndPointIDFromUniqueEPIDString(uniqueEPIDString); + } + + public static string GetAccountFromUniqueEPIDString(string uniqueEPIDString) + { + string[] accountGuid = uniqueEPIDString.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + return accountGuid[0].ToLowerInvariant(); + } + + public static Guid GetEndPointIDFromUniqueEPIDString(string uniqueEPIDString) + { + string[] accountGuid = uniqueEPIDString.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + try + { + if (accountGuid.Length > 0) + { + return new Guid(accountGuid[1]); + } + else + { + return Guid.Empty; + } + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "GetEndPointIDFromUniqueEPIDString error, empty GUID returned. StackTrace: " + ex.StackTrace); + return Guid.Empty; + } + } + + public override string ToString() + { + return Account + ";" + Id.ToString("B") + " " + ClientCapacities + ":" + ClientCapacitiesEx; + } + } + + [Serializable] + public class PrivateEndPointData : EndPointData + { + private string name = string.Empty; + public const string EveryWherePlace = "Everywhere"; + + /// + /// The EpName xml node of UBX command payload. + /// + public string Name + { + get + { + return name; + } + set + { + name = value; + } + } + + private string clientType = string.Empty; + + /// + /// The ClientType xml node of UBX command payload. + /// + public string ClientType + { + get + { + return clientType; + } + set + { + clientType = value; + } + } + + private bool idle = false; + + /// + /// The Idle xml node of UBX command payload. + /// + public bool Idle + { + get + { + return idle; + } + set + { + idle = value; + } + } + + private PresenceStatus state = PresenceStatus.Unknown; + + public PresenceStatus State + { + get + { + return state; + } + set + { + state = value; + } + } + + public PrivateEndPointData(string account, Guid epId) + : base(account, epId) + { + if (epId == NSMessageHandler.MachineGuid) + { + Name = Environment.MachineName; + } + + if (epId == Guid.Empty) + { + Name = EveryWherePlace; + } + } + + public PrivateEndPointData(string uniqueEPIDString) + : base(uniqueEPIDString) + { + } + } +}; diff --git a/MSNPSharp/EventArgs.cs b/MSNPSharp/EventArgs.cs new file mode 100644 index 0000000..e81b882 --- /dev/null +++ b/MSNPSharp/EventArgs.cs @@ -0,0 +1,1001 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + using MSNPSharp.DataTransfer; + + /// + /// Used when contact changed its status. + /// + [Serializable()] + public class ContactStatusChangedEventArgs : StatusChangedEventArgs + { + Contact contact; + + /// + /// The contact who changed its status. + /// + public Contact Contact + { + get + { + return contact; + } + set + { + contact = value; + } + } + + public ContactStatusChangedEventArgs(Contact contact, + PresenceStatus oldStatus) + :base(oldStatus) + { + Contact = contact; + } + } + + /// + /// Used when any contect event occured. + /// + [Serializable()] + public class BaseContactEventArgs : EventArgs + { + protected Contact contact = null; + + public BaseContactEventArgs(Contact contact) + { + this.contact = contact; + } + } + + [Serializable()] + public class ContactEventArgs : BaseContactEventArgs + { + /// + /// The contact raise the event. + /// + public Contact Contact + { + get + { + return contact; + } + set + { + contact = value; + } + } + + public ContactEventArgs(Contact contact) + : base(contact) + { + } + } + + [Serializable()] + public class ContactConversationEventArgs : ContactEventArgs + { + private Guid epoint = Guid.Empty; + + public Guid EndPoint + { + get { return epoint; } + } + + public ContactConversationEventArgs(Contact contact, Guid endPoint) + :base(contact) + { + epoint = endPoint; + } + } + + /// + /// Use when user's sign in places changed. + /// + public class PlaceChangedEventArgs : EventArgs + { + private string placeName = string.Empty; + private Guid placeId = Guid.Empty; + private PlaceChangedReason reason = PlaceChangedReason.None; + + public PlaceChangedReason Reason + { + get { return reason; } + } + + public string PlaceName + { + get { return placeName; } + } + + + public Guid PlaceId + { + get { return placeId; } + } + + private PlaceChangedEventArgs() + : base() + { + } + + public PlaceChangedEventArgs(Guid id, string name, PlaceChangedReason action) + : base() + { + placeId = id; + placeName = name; + reason = action; + } + + } + + /// + /// Used when a contact changed its status. + /// + [Serializable()] + public class StatusChangedEventArgs : EventArgs + { + private PresenceStatus oldStatus; + + public PresenceStatus OldStatus + { + get + { + return oldStatus; + } + set + { + oldStatus = value; + } + } + + public StatusChangedEventArgs(PresenceStatus oldStatus) + { + OldStatus = oldStatus; + } + } + + /// + /// Used in events where a exception is raised. Via these events the client programmer + /// can react on these exceptions. + /// + [Serializable()] + public class ExceptionEventArgs : EventArgs + { + /// + /// + private Exception _exception; + + /// + /// The exception that was raised + /// + public Exception Exception + { + get + { + return _exception; + } + set + { + _exception = value; + } + } + + /// + /// Constructor. + /// + /// + public ExceptionEventArgs(Exception e) + { + _exception = e; + } + } + + /// + /// Base class for all message received event args. + /// + [Serializable()] + public class BaseMessageReceivedEventArgs : BaseContactEventArgs + { + /// + /// The sender. + /// + public Contact Sender + { + get + { + return contact; + } + } + + internal BaseMessageReceivedEventArgs(Contact sender) + : base(sender) + { + } + } + + + /// + /// Used as event argument when a textual message is send. + /// + [Serializable()] + public class TextMessageEventArgs : BaseMessageReceivedEventArgs + { + /// + /// + private TextMessage message; + + /// + /// The message send. + /// + public TextMessage Message + { + get + { + return message; + } + set + { + message = value; + } + } + + /// + /// Constructor. + /// + /// + /// + public TextMessageEventArgs(TextMessage message, Contact sender) + : base(sender) + { + Message = message; + } + } + + [Serializable()] + public class WinkEventArgs : BaseMessageReceivedEventArgs + { + private Wink wink; + + public Wink Wink + { + get + { + return wink; + } + set + { + wink = value; + } + } + + public WinkEventArgs(Contact contact, Wink wink) + :base(contact) + { + this.wink = wink; + } + } + + /// + /// Used as event argument when a emoticon definition is send. + /// + [Serializable()] + public class EmoticonDefinitionEventArgs : BaseMessageReceivedEventArgs + { + + /// + /// + private Emoticon emoticon; + + /// + /// The emoticon which is defined + /// + public Emoticon Emoticon + { + get + { + return emoticon; + } + set + { + emoticon = value; + } + } + + /// + /// Constructor. + /// + /// + /// + public EmoticonDefinitionEventArgs(Contact sender, Emoticon emoticon) + :base(sender) + { + this.emoticon = emoticon; + } + } + + /// + /// Used when a list (FL, Al, BL, RE) is received via synchronize or on request. + /// + [Serializable()] + public class ListReceivedEventArgs : EventArgs + { + /// + /// + private MSNLists affectedList = MSNLists.None; + + /// + /// The list which was send by the server + /// + public MSNLists AffectedList + { + get + { + return affectedList; + } + set + { + affectedList = value; + } + } + + /// + /// Constructory. + /// + /// + public ListReceivedEventArgs(MSNLists affectedList) + { + AffectedList = affectedList; + } + } + + /// + /// Used when the local user is signed off. + /// + [Serializable()] + public class SignedOffEventArgs : EventArgs + { + /// + /// + private SignedOffReason signedOffReason; + + /// + /// The list which was send by the server + /// + public SignedOffReason SignedOffReason + { + get + { + return signedOffReason; + } + set + { + signedOffReason = value; + } + } + + /// + /// Constructor. + /// + /// + public SignedOffEventArgs(SignedOffReason signedOffReason) + { + this.signedOffReason = signedOffReason; + } + } + + /// + /// Used as event argument when an answer to a ping is received. + /// + [Serializable()] + public class PingAnswerEventArgs : EventArgs + { + /// + /// The number of seconds to wait before sending another PNG, + /// and is reset to 50 every time a command is sent to the server. + /// In environments where idle connections are closed after a short time, + /// you should send a command to the server (even if it's just a PNG) at least this often. + /// Note: MSNPSharp does not handle this! E.g. if you experience unexpected connection dropping call the Ping() method. + /// + public int SecondsToWait + { + get + { + return secondsToWait; + } + set + { + secondsToWait = value; + } + } + + /// + /// + private int secondsToWait; + + + /// + /// + /// + public PingAnswerEventArgs(int seconds) + { + SecondsToWait = seconds; + } + } + + /// + /// Used as event argument when any contact list mutates. + /// + [Serializable()] + public class ListMutateEventArgs : ContactEventArgs + { + /// + /// + private MSNLists affectedList = MSNLists.None; + + /// + /// The list which mutated. + /// + public MSNLists AffectedList + { + get + { + return affectedList; + } + set + { + affectedList = value; + } + } + + /// + /// Constructor + /// + /// + /// + public ListMutateEventArgs(Contact contact, MSNLists affectedList) + : base(contact) + { + AffectedList = affectedList; + } + } + + /// + /// Used as event argument when msn sends us an error. + /// + [Serializable()] + public class MSNErrorEventArgs : EventArgs + { + /// + /// + private MSNError msnError; + + /// + /// The error that occurred + /// + public MSNError MSNError + { + get + { + return msnError; + } + set + { + msnError = value; + } + } + + /// + /// Constructory. + /// + /// + public MSNErrorEventArgs(MSNError msnError) + { + this.msnError = msnError; + } + } + + /// + /// Base class for circle event arg. + /// + public class BaseCircleEventArgs : EventArgs + { + protected Circle circle = null; + internal BaseCircleEventArgs(Circle circle) + { + this.circle = circle; + } + } + + /// + /// Used as event argument when a is affected. + /// + [Serializable()] + public class CircleEventArgs : BaseCircleEventArgs + { + protected Contact remoteMember = null; + + /// + /// The affected contact group + /// + public Circle Circle + { + get + { + return circle; + } + } + + /// + /// Constructor, mostly used internal by the library. + /// + /// + internal CircleEventArgs(Circle circle) + :base(circle) + { + } + + /// + /// Constructor, mostly used internal by the library. + /// + /// + /// The affected Contact. + internal CircleEventArgs(Circle circle, Contact remote) + :base(circle) + { + remoteMember = remote; + } + } + + /// + /// Used when a event related to circle member operaion fired. + /// + [Serializable()] + public class CircleMemberEventArgs : CircleEventArgs + { + /// + /// The contact member raise the event. + /// + public Contact Member + { + get + { + return remoteMember; + } + } + + internal CircleMemberEventArgs(Circle circle, Contact member) + : base(circle, member) + { + } + } + + [Serializable()] + public class CircleStatusChangedEventArgs: StatusChangedEventArgs + { + protected Circle circle = null; + + /// + /// The circle which changed its status. + /// + public Circle Circle + { + get { return circle; } + } + + internal CircleStatusChangedEventArgs(Circle circle, PresenceStatus oldStatus) + : base(oldStatus) + { + this.circle = circle; + } + } + + [Serializable()] + public class CircleMemberStatusChanged : CircleStatusChangedEventArgs + { + private Contact circleMember = null; + + protected Contact CircleMember + { + get { return circleMember; } + } + + internal CircleMemberStatusChanged(Circle circle, Contact member, PresenceStatus oldStatus) + : base(circle, oldStatus) + { + circleMember = member; + } + + } + + /// + /// Event argument used for ContactService.JoinCircleInvitationReceived event. + /// + [Obsolete("Inviter is no more supported by Microsoft.")] + [Serializable()] + public class JoinCircleInvitationEventArgs : CircleEventArgs + { + + /// + /// who send this invitation. + /// + public CircleInviter Inviter + { + get { return remoteMember as CircleInviter; } + } + + internal JoinCircleInvitationEventArgs(Circle circle, CircleInviter invitor) + : base(circle) + { + } + } + + /// + /// Event argument used for receiving text messages from a circle. + /// + [Serializable()] + public class CircleTextMessageEventArgs : TextMessageEventArgs + { + protected Contact triggerMember = null; + + public CircleTextMessageEventArgs(TextMessage textMessage, Circle sender, Contact triggerMember) + : base(textMessage, sender) + { + this.triggerMember = triggerMember; + } + + /// + /// The circle message send from. + /// + public new Circle Sender + { + get + { + return base.Sender as Circle; + } + } + + /// + /// The circle member who send this message. + /// + public Contact TriggerMember + { + get + { + return triggerMember; + } + } + } + + /// + /// Event argument used when a user's property has been changed. + /// + public class DisplayImageChangedEventArgs : EventArgs + { + private bool callFromContactManager = false; + private DisplayImageChangedType status = DisplayImageChangedType.None; + private DisplayImage newDisplayImage = null; + + public DisplayImage NewDisplayImage + { + get + { + return newDisplayImage; + } + } + + /// + /// The reason that fires event. + /// + public DisplayImageChangedType Status + { + get + { + return status; + } + } + + /// + /// Whether we need to do display image synchronize. + /// + internal bool CallFromContactManager + { + get + { + return callFromContactManager; + } + } + + private DisplayImageChangedEventArgs() + { + } + + internal DisplayImageChangedEventArgs(DisplayImage dispImage, DisplayImageChangedType type, bool needSync) + { + status = type; + callFromContactManager = needSync; + newDisplayImage = dispImage; + } + + internal DisplayImageChangedEventArgs(DisplayImageChangedEventArgs arg, bool needSync) + { + status = arg.Status; + callFromContactManager = needSync; + newDisplayImage = arg.NewDisplayImage; + } + + public DisplayImageChangedEventArgs(DisplayImage dispImage, DisplayImageChangedType type) + { + status = type; + callFromContactManager = false; + newDisplayImage = dispImage; + } + } + + /// + /// Use when receiving messages from IM network other than MSN. + /// + public class CrossNetworkMessageEventArgs : EventArgs + { + private Contact from = null; + + /// + /// The sender of message. + /// + public Contact From + { + get { return from; } + } + + private Contact to = null; + + /// + /// The receiver of the message. + /// + public Contact To + { + get { return to; } + } + + private int messageType = 0; + + /// + /// The type of message received. Please refer to + /// + public NetworkMessageType MessageType + { + get + { + return (NetworkMessageType)messageType; + } + } + + + private NetworkMessage message = null; + + /// + /// The message received. + /// + public NetworkMessage Message + { + get { return message; } + } + + /// + /// The IM network we get the message. + /// + public NetworkType Network + { + get + { + if (From != null) + { + switch (From.ClientType) + { + case ClientType.EmailMember: + return NetworkType.Yahoo; + + case ClientType.PhoneMember: + return NetworkType.Mobile; + + default: + return NetworkType.WindowsLive; + } + } + + return NetworkType.None; + } + } + + /// + /// Constructor + /// + /// The message sender + /// The message receiver + /// Message type, cast from + /// The message body + public CrossNetworkMessageEventArgs(Contact sender, Contact receiver, int type, NetworkMessage msg) + { + from = sender; + to = receiver; + messageType = type; + message = msg; + } + } + + /// + /// Used to notify client programmer after the MSN data object transfer completed. + /// + public class MSNObjectDataTransferCompletedEventArgs : EventArgs + { + private MSNObject clientData = null; + private bool aborted = false; + private Contact remote = null; + private Guid remoteEndPointID = Guid.Empty; + + /// + /// Another site associated with this object's transfer. + /// + public Contact RemoteContact + { + get { return remote; } + } + + /// + /// The location of remote contact. + /// + public Guid RemoteContactEndPointID + { + get { return remoteEndPointID; } + } + + /// + /// Transfer failed. + /// + public bool Aborted + { + get { return aborted; } + } + + /// + /// The target msnobject. + /// + public MSNObject ClientData + { + get { return clientData; } + } + + protected MSNObjectDataTransferCompletedEventArgs() + : base() + { + } + + public MSNObjectDataTransferCompletedEventArgs(MSNObject clientdata, bool abort, Contact remoteContact, Guid remoteEPID) + { + if (clientdata == null) + throw new ArgumentNullException("clientdata"); + + clientData = clientdata; + aborted = abort; + remote = remoteContact; + remoteEndPointID = remoteEPID; + } + } + + public class ConversationMSNObjectDataTransferCompletedEventArgs : MSNObjectDataTransferCompletedEventArgs + { + private P2PTransferSession transferSession = null; + + public P2PTransferSession TransferSession + { + get + { + return transferSession; + } + + private set + { + transferSession = value; + } + } + + public ConversationMSNObjectDataTransferCompletedEventArgs(P2PTransferSession sender, MSNObjectDataTransferCompletedEventArgs e) + : base(e.ClientData, e.Aborted, e.RemoteContact, e.RemoteContactEndPointID) + { + TransferSession = sender; + } + } + + /// + /// Use to notify a has ended. + /// + public class ConversationEndEventArgs : EventArgs + { + private Conversation conversation = null; + + public Conversation Conversation + { + get { return conversation; } + } + + protected ConversationEndEventArgs() + : base() + { + } + + public ConversationEndEventArgs(Conversation convers) + { + conversation = convers; + } + } + + /// + /// Used to notify client programmer that the remote owner of a conversation has been changed. + /// + public class ConversationRemoteOwnerChangedEventArgs : EventArgs + { + private Contact oldRemoteOwner = null; + + /// + /// The remote owner of the conversation before change. + /// + public Contact OldRemoteOwner + { + get { return oldRemoteOwner; } + } + + private Contact newRemoteOwner = null; + + /// + /// The new remote owner after the old one has left the conversation. + /// + public Contact NewRemoteOwner + { + get { return newRemoteOwner; } + } + + private ConversationRemoteOwnerChangedEventArgs() + { + } + + public ConversationRemoteOwnerChangedEventArgs(Contact oldOwner, Contact newOwner) + { + oldRemoteOwner = oldOwner; + newRemoteOwner = newOwner; + } + } +}; diff --git a/MSNPSharp/Framework.cs b/MSNPSharp/Framework.cs new file mode 100644 index 0000000..0cac160 --- /dev/null +++ b/MSNPSharp/Framework.cs @@ -0,0 +1,358 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Resources; +using System.Globalization; +using System.Threading; +using System.Net; +using System.IO; +using System.Runtime.Serialization; +using System.Xml; +using System.Xml.Serialization; +using System.Diagnostics; +using System.Collections; + +namespace MSNPSharp.Framework +{ + using MSNPSharp.MSNWS.MSNSecurityTokenService; + + internal class ContentType + { + // Fields + internal const string ApplicationBase = "application"; + internal const string ApplicationOctetStream = "application/octet-stream"; + internal const string ApplicationSoap = "application/soap+xml"; + internal const string ApplicationXml = "application/xml"; + internal const string ContentEncoding = "Content-Encoding"; + internal const string TextBase = "text"; + internal const string TextHtml = "text/html"; + internal const string TextPlain = "text/plain"; + internal const string TextXml = "text/xml"; + + // Methods + private ContentType() + { + } + + internal static string Compose(string contentType, Encoding encoding) + { + return Compose(contentType, encoding, null); + } + + internal static string Compose(string contentType, Encoding encoding, string action) + { + if ((encoding == null) && (action == null)) + { + return contentType; + } + StringBuilder builder = new StringBuilder(contentType); + if (encoding != null) + { + builder.Append("; charset="); + builder.Append(encoding.WebName); + } + if (action != null) + { + builder.Append("; action=\""); + builder.Append(action); + builder.Append("\""); + } + return builder.ToString(); + } + + internal static string GetAction(string contentType) + { + return GetParameter(contentType, "action"); + } + + internal static string GetBase(string contentType) + { + int index = contentType.IndexOf(';'); + if (index >= 0) + { + return contentType.Substring(0, index); + } + return contentType; + } + + internal static string GetCharset(string contentType) + { + return GetParameter(contentType, "charset"); + } + + internal static string GetMediaType(string contentType) + { + string str = GetBase(contentType); + int index = str.IndexOf('/'); + if (index >= 0) + { + return str.Substring(0, index); + } + return str; + } + + private static string GetParameter(string contentType, string paramName) + { + string[] strArray = contentType.Split(new char[] { ';' }); + for (int i = 1; i < strArray.Length; i++) + { + string strA = strArray[i].TrimStart(null); + if (string.Compare(strA, 0, paramName, 0, paramName.Length, StringComparison.OrdinalIgnoreCase) == 0) + { + int index = strA.IndexOf('=', paramName.Length); + if (index >= 0) + { + return strA.Substring(index + 1).Trim(new char[] { ' ', '\'', '"', '\t' }); + } + } + } + return null; + } + + internal static bool IsApplication(string contentType) + { + return (string.Compare(GetMediaType(contentType), "application", StringComparison.OrdinalIgnoreCase) == 0); + } + + internal static bool IsHtml(string contentType) + { + return (string.Compare(GetBase(contentType), "text/html", StringComparison.OrdinalIgnoreCase) == 0); + } + + internal static bool IsSoap(string contentType) + { + string strA = GetBase(contentType); + if (string.Compare(strA, "text/xml", StringComparison.OrdinalIgnoreCase) != 0) + { + return (string.Compare(strA, "application/soap+xml", StringComparison.OrdinalIgnoreCase) == 0); + } + return true; + } + + internal static bool IsXml(string contentType) + { + string strA = GetBase(contentType); + if (string.Compare(strA, "text/xml", StringComparison.OrdinalIgnoreCase) != 0) + { + return (string.Compare(strA, "application/xml", StringComparison.OrdinalIgnoreCase) == 0); + } + return true; + } + + internal static bool MatchesBase(string contentType, string baseContentType) + { + return (string.Compare(GetBase(contentType), baseContentType, StringComparison.OrdinalIgnoreCase) == 0); + } + } + + internal class RequestResponseUtils + { + // Methods + private RequestResponseUtils() + { + } + + internal static int GetBufferSize(int contentLength) + { + if (contentLength == -1) + { + return 0x1f40; + } + if (contentLength <= 0x3e80) + { + return contentLength; + } + return 0x3e80; + } + + internal static Encoding GetEncoding(string contentType) + { + string charset = ContentType.GetCharset(contentType); + Encoding encoding = null; + try + { + if ((charset != null) && (charset.Length > 0)) + { + encoding = Encoding.GetEncoding(charset); + } + } + catch (Exception exception) + { + if (((exception is ThreadAbortException) || (exception is StackOverflowException)) || (exception is OutOfMemoryException)) + { + throw; + } + } + + + if (encoding != null) + { + return encoding; + } + return new ASCIIEncoding(); + } + + internal static Encoding GetEncoding2(string contentType) + { + if (!ContentType.IsApplication(contentType)) + { + return GetEncoding(contentType); + } + string charset = ContentType.GetCharset(contentType); + Encoding encoding = null; + try + { + if ((charset != null) && (charset.Length > 0)) + { + encoding = Encoding.GetEncoding(charset); + } + } + catch (Exception exception) + { + if (((exception is ThreadAbortException) || (exception is StackOverflowException)) || (exception is OutOfMemoryException)) + { + throw; + } + } + + return encoding; + } + + internal static string ReadResponse(WebResponse response) + { + return ReadResponse(response, response.GetResponseStream()); + } + + internal static string ReadResponse(WebResponse response, Stream stream) + { + string str; + Encoding encoding = GetEncoding(response.ContentType); + if (encoding == null) + { + encoding = Encoding.Default; + } + StreamReader reader = new StreamReader(stream, encoding, true); + try + { + str = reader.ReadToEnd(); + } + finally + { + stream.Close(); + } + return str; + } + + internal static Stream StreamToMemoryStream(Stream stream) + { + int num; + MemoryStream stream2 = new MemoryStream(0x400); + byte[] buffer = new byte[0x400]; + while ((num = stream.Read(buffer, 0, buffer.Length)) != 0) + { + stream2.Write(buffer, 0, num); + } + stream2.Position = 0L; + return stream2; + } + + } + + + public class XmlSpecialNSPrefixTextWriter : XmlTextWriter + { + private enum XmlWriteState + { + None, + EvelopeWritten, + SpecialNSWritten, + BeginWriteBody + } + + private XmlWriteState state = XmlWriteState.None; + + public XmlSpecialNSPrefixTextWriter(TextWriter w) + : base(w) + { + } + + public XmlSpecialNSPrefixTextWriter(Stream w, Encoding encoding) + : base(w, encoding) + { + } + + public XmlSpecialNSPrefixTextWriter(string filename, Encoding encoding) + : base(filename, encoding) + { + } + + public override void WriteStartElement(string prefix, string localName, string ns) + { + base.WriteStartElement(prefix, localName, ns); + + if (localName == "Envelope" && state == XmlWriteState.None) + { + state = XmlWriteState.EvelopeWritten; + + if (state == XmlWriteState.EvelopeWritten) + { + //WriteAttributeString("xmlns", "ps", null, @"http://schemas.microsoft.com/Passport/SoapServices/PPCRL"); + //WriteAttributeString("xmlns", "psf", null, @"http://schemas.microsoft.com/Passport/SoapServices/SOAPFault"); + + WriteAttributeString("xmlns", "wsse", null, @"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); + WriteAttributeString("xmlns", "wssc", null, @"http://schemas.xmlsoap.org/ws/2005/02/sc"); + WriteAttributeString("xmlns", "wsu", null, @"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"); + WriteAttributeString("xmlns", "wst", null, @"http://schemas.xmlsoap.org/ws/2005/02/trust"); + WriteAttributeString("xmlns", "wsp", null, @"http://schemas.xmlsoap.org/ws/2004/09/policy"); + WriteAttributeString("xmlns", "wsa", null, @"http://www.w3.org/2005/08/addressing"); + + WriteAttributeString("xmlns", "saml", null, @"urn:oasis:names:tc:SAML:1.0:assertion"); + + state = XmlWriteState.SpecialNSWritten; + } + } + + if (localName == "Assertion" && state == XmlWriteState.SpecialNSWritten) + { + WriteAttributeString("xmlns", "saml", null, @"urn:oasis:names:tc:SAML:1.0:assertion"); + } + + if (localName == "Body" && state != XmlWriteState.BeginWriteBody) + { + state = XmlWriteState.BeginWriteBody; + } + } + } +} diff --git a/MSNPSharp/IO/DeltasList.cs b/MSNPSharp/IO/DeltasList.cs new file mode 100644 index 0000000..d2ec4d8 --- /dev/null +++ b/MSNPSharp/IO/DeltasList.cs @@ -0,0 +1,416 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Text; +using System.Xml.Serialization; +using System.Collections.Generic; + +namespace MSNPSharp.IO +{ + using MSNPSharp.MSNWS.MSNABSharingService; + using MSNPSharp.Core; +using System.Drawing; + + /// + /// Storage class for deltas request + /// + [Serializable] + public class DeltasList : MCLSerializer + { + private const int MaxSlot = 1000; + + private SerializableDictionary cacheKeys = new SerializableDictionary(0); + private SerializableDictionary preferredHosts = new SerializableDictionary(0); + private SerializableDictionary userTileSlots = new SerializableDictionary(MaxSlot); + private SerializableDictionary visitCount = new SerializableDictionary(MaxSlot); + private SerializableDictionary userImageRelationships = new SerializableDictionary(); + + public SerializableDictionary UserImageRelationships + { + get { return userImageRelationships; } + set { userImageRelationships = value; } + } + + + public SerializableDictionary VisitCount + { + get { return visitCount; } + set { visitCount = value; } + } + + /// + /// Data structure that store the user's display images. + /// + public SerializableDictionary UserTileSlots + { + get { return userTileSlots; } + set { userTileSlots = value; } + } + + /// + /// CacheKeys for webservices. + /// + public SerializableDictionary CacheKeys + { + get + { + return cacheKeys; + } + set + { + cacheKeys = value; + } + } + + /// + /// Preferred hosts for different methods. + /// + public SerializableDictionary PreferredHosts + { + get + { + return preferredHosts; + } + set + { + preferredHosts = value; + } + } + + #region Profile + private OwnerProfile profile = new OwnerProfile(); + + /// + /// Profile of current user. + /// + [XmlElement("Profile")] + public OwnerProfile Profile + { + get + { + return profile; + } + set + { + profile = value; + } + } + + #endregion + + #region Private methods + + private bool HasRelationship(string siblingAccount) + { + lock (UserImageRelationships) + return UserImageRelationships.ContainsKey(siblingAccount.ToLowerInvariant()); + } + + private bool HasImage(string imageKey) + { + lock (UserTileSlots) + return UserTileSlots.ContainsKey(imageKey); + } + + private bool HasRelationshipAndImage(string siblingAccount, out string imageKey) + { + imageKey = string.Empty; + if (!HasRelationship(siblingAccount)) + { + return false; + } + + string imgKey = string.Empty; + lock (UserImageRelationships) + imgKey = UserImageRelationships[siblingAccount.ToLowerInvariant()]; + + if (!HasImage(imgKey)) + return false; + + imageKey = imgKey; + return true; + } + + private void AddImage(string imageKey, byte[] data) + { + if (HasImage(imageKey)) + return; + + lock (UserTileSlots) + UserTileSlots[imageKey] = data; + } + + private void AddRelationship(string siblingAccount, string imageKey) + { + lock (UserImageRelationships) + UserImageRelationships[siblingAccount.ToLowerInvariant()] = imageKey; + } + + private void AddImageAndRelationship(string siblingAccount, string imageKey, byte[] data) + { + AddImage(imageKey, data); + AddRelationship(siblingAccount, imageKey); + } + + private bool RemoveImage(string imageKey) + { + bool noerror = true; + + lock (UserTileSlots) + noerror |= UserTileSlots.Remove(imageKey); + + lock (VisitCount) + noerror |= VisitCount.Remove(imageKey); + + lock (UserImageRelationships) + { + Dictionary cp = new Dictionary(UserImageRelationships); + foreach (string account in cp.Keys) + { + if (cp[account] == imageKey) + UserImageRelationships.Remove(account); + } + } + + return noerror; + } + + private bool RemoveRelationship(string siblingAccount) + { + if (!HasRelationship(siblingAccount)) + return false; + + lock (UserImageRelationships) + { + string key = UserImageRelationships[siblingAccount]; + UserImageRelationships.Remove(siblingAccount); + } + + return true; + } + + /// + /// + /// + /// + /// This function does NOT exam whether the correspondent slot exist. + private uint IncreaseVisitCount(string imageKey) + { + lock (VisitCount) + { + if (!VisitCount.ContainsKey(imageKey)) + VisitCount[imageKey] = 0; + + return ++VisitCount[imageKey]; + } + } + + private uint DecreaseVisitCount(string imageKey) + { + lock (VisitCount) + { + if (!VisitCount.ContainsKey(imageKey)) + return uint.MinValue; + + if (VisitCount[imageKey] > 0) + { + return --VisitCount[imageKey]; + } + } + + //error + return 0; + } + + private bool GetLeastVisitImage(out string imageKey) + { + imageKey = string.Empty; + lock (VisitCount) + { + if (VisitCount.Count == 0) + return false; + uint minValue = uint.MaxValue; + uint maxValue = 0; + ulong sum = 0; + + string lastKey = string.Empty; + + foreach (string key in VisitCount.Keys) + { + if (VisitCount[key] <= minValue) + { + minValue = VisitCount[key]; + lastKey = key; + } + + if (VisitCount[key] >= maxValue) + maxValue = VisitCount[key]; + + sum += VisitCount[key]; + } + + if (string.IsNullOrEmpty(lastKey)) + return false; + + imageKey = lastKey; + if (maxValue == uint.MaxValue) //Prevent overflow. + { + uint avg = (uint)(sum / (ulong)VisitCount.Count); + if (avg == uint.MaxValue) + avg = 0; + + lock (VisitCount) + { + Dictionary cp = new Dictionary(VisitCount); + foreach (string imgKey in cp.Keys) + { + if (cp[imgKey] == uint.MaxValue) + VisitCount[imgKey] = avg; + } + } + } + + return true; + + } + } + + #endregion + + #region Internal Methods + + internal byte[] GetRawImageDataBySiblingString(string siblingAccount, out string imageKey) + { + imageKey = string.Empty; + if (HasRelationshipAndImage(siblingAccount, out imageKey)) + { + lock (UserTileSlots) + { + IncreaseVisitCount(imageKey); + return UserTileSlots[imageKey]; + } + + } + + return null; + } + + internal bool SaveImageAndRelationship(string siblingAccount, string imageKey, byte[] userTile) + { + + lock (UserTileSlots) + { + if (UserTileSlots.Count == MaxSlot) + { + //The heaven is full. + string deleteKey = string.Empty; + if (GetLeastVisitImage(out deleteKey)) + { + RemoveImage(deleteKey); + } + else + { + //OMG no one want to give a place? + return false; + } + } + + AddImageAndRelationship(siblingAccount, imageKey, userTile); + } + + return true; + } + + #endregion + + #region Public methods + + /// + /// Empty all of the lists + /// + public void Empty() + { + + } + + /// + /// Truncate file. This is useful after calling of Addressbook.Save + /// + public void Truncate() + { + Empty(); + Save(true); + } + + public static DeltasList LoadFromFile(string filename, MclSerialization st, NSMessageHandler handler, bool useCache) + { + return (DeltasList)LoadFromFile(filename, st, typeof(DeltasList), handler, useCache); + } + + #endregion + + #region Overrides + + /// + /// Save the into a specified file. + /// + /// + public override void Save(string filename) + { + FileName = filename; + Save(false); + } + + public override void Save() + { + Save(false); + } + + public void Save(bool saveImmediately) + { + Version = Properties.Resources.DeltasListVersion; + + if (saveImmediately == false && + File.Exists(FileName) && + File.GetLastWriteTime(FileName) > DateTime.Now.AddSeconds(-5)) + { + return; + } + + base.Save(FileName); + } + + #endregion + } +}; diff --git a/MSNPSharp/IO/IO.cs b/MSNPSharp/IO/IO.cs new file mode 100644 index 0000000..61164ca --- /dev/null +++ b/MSNPSharp/IO/IO.cs @@ -0,0 +1,605 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Text; +using System.Threading; +using System.Diagnostics; +using System.IO.Compression; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Runtime.InteropServices; + +namespace MSNPSharp.IO +{ + #region MclFileStruct + [StructLayout(LayoutKind.Sequential)] + internal struct MclFileStruct + { + public byte[] content; + } + + #endregion + + #region MclInfo + + internal class MclInfo + { + private MclFile file; + private DateTime lastChange; + + public MclInfo(MclFile pfile) + { + file = pfile; + if (System.IO.File.Exists(file.FileName)) + { + lastChange = System.IO.File.GetLastWriteTime(file.FileName); + } + } + + /// + /// Get whether the file was changed and refresh the property. + /// + /// + public bool Refresh() + { + if (file != null && System.IO.File.Exists(file.FileName)) + { + bool changed = lastChange.CompareTo(System.IO.File.GetLastWriteTime(file.FileName)) != 0; + lastChange = System.IO.File.GetLastWriteTime(file.FileName); + return changed; + } + + return false; + } + + /// + /// Inner file + /// + public MclFile File + { + get + { + return file; + } + } + + /// + /// Last written date + /// + public DateTime LastChange + { + get + { + return lastChange; + } + } + } + + #endregion + + /// + /// Mcl serialization to load/save contact list files. + /// A mcl file can be serialized as both compressed and encrypted formats. + /// + [Flags] + public enum MclSerialization + { + /// + /// No serialization, use plain text. + /// + None = 0, + /// + /// Use compression. + /// + Compression = 1, + /// + /// Use cryptography. + /// + Cryptography = 2 + } + + #region MclFile + + /// + /// File class used to save userdata. + /// + public sealed class MclFile + { + /// + /// Signature for compressed file - mcl. + /// + public static readonly byte[] MclBytes = new byte[] { (byte)'m', (byte)'c', (byte)'l' }; + /// + /// Signature for encrypted file - mpw, Mr Pang Wu :) + /// + public static readonly byte[] MpwBytes = new byte[] { (byte)'m', (byte)'p', (byte)'w' }; + /// + /// Signature for compressed+encrypted file - mcp. + /// + public static readonly byte[] McpBytes = new byte[] { (byte)'m', (byte)'c', (byte)'p' }; + + private MclSerialization mclSerialization = MclSerialization.None; + private string fileName = String.Empty; + private byte[] sha256Password = new byte[32]; + private byte[] xmlData; + + public MclFile(string filename, MclSerialization st, FileAccess access, string password) + { + fileName = filename; + mclSerialization = st; + + if (!String.IsNullOrEmpty(password)) + { + using (SHA256Managed sha256 = new SHA256Managed()) + sha256Password = sha256.ComputeHash(Encoding.UTF8.GetBytes(password)); + } + + if ((access & FileAccess.Read) == FileAccess.Read) + xmlData = GetStruct().content; + } + + /// + /// Opens filename and fills the with uncompressed data if file is opened for reading. + /// + /// Name of file + /// Use of compression when SAVING file. + /// The is filled if the file is opened for reading + public MclFile(string filename, bool nocompress, FileAccess access) + : this(filename, nocompress ? MclSerialization.None : MclSerialization.Compression, access, null) + { + } + + #region Public method + public void Save(string filename) + { + WriteAllBytes(filename, FillFileStruct(xmlData)); + } + + public void Save() + { + Save(fileName); + } + + /// + /// Save the file and set its hidden attribute to true + /// + /// + /// + public void Save(string filename, bool saveToHiddenFile) + { + WriteAllBytes(filename, FillFileStruct(xmlData)); + if (saveToHiddenFile) + { + lock (this) + { + File.SetAttributes(filename, FileAttributes.Hidden); + } + } + } + + /// + /// Save the file and set its hidden attribute to true + /// + public void SaveAndHide() + { + Save(fileName, true); + } + + #endregion + + #region Properties + + /// + /// Name of file + /// + public string FileName + { + get + { + return fileName; + } + set + { + fileName = value; + } + } + + /// + /// XML data + /// + public byte[] Content + { + get + { + return xmlData; + } + set + { + xmlData = value; + } + } + + /// + /// Don't use compression when SAVING. + /// + public bool NoCompression + { + get + { + return mclSerialization == MclSerialization.None; + } + } + + #endregion + + #region Private + + private void WriteAllBytes(string filename, byte[] content) + { + DateTime beginTime = DateTime.Now; + fileName = filename; + + if (content != null) + { + lock (this) + { + try + { + if (File.Exists(filename)) + File.SetAttributes(filename, FileAttributes.Normal); + + File.WriteAllBytes(filename, content); + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "MCL File write error: " + ex.Message); + } + } + } + + TimeSpan timeConsume = DateTime.Now - beginTime; + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "<" + this.GetType().ToString() + "> Write raw file time (by ticks): " + timeConsume.Ticks); + } + + private static byte[] Compress(byte[] buffer) + { + DateTime beginTime = DateTime.Now; + MemoryStream destms = new MemoryStream(); + GZipStream zipsm = new GZipStream(destms, CompressionMode.Compress, true); + zipsm.Write(buffer, 0, buffer.Length); + zipsm.Close(); + + TimeSpan timeConsume = DateTime.Now - beginTime; + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, " Compress time (by ticks): " + timeConsume.Ticks); + return destms.ToArray(); + } + + private static byte[] Decompress(byte[] compresseddata) + { + DateTime beginTime = DateTime.Now; + MemoryStream destms = new MemoryStream(); + MemoryStream ms = new MemoryStream(compresseddata); + ms.Position = 0; + + int read; + byte[] decompressdata = new byte[8192]; + GZipStream zipsm = new GZipStream(ms, CompressionMode.Decompress, true); + + while ((read = zipsm.Read(decompressdata, 0, decompressdata.Length)) > 0) + { + destms.Write(decompressdata, 0, read); + } + + zipsm.Close(); + TimeSpan timeConsume = DateTime.Now - beginTime; + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, " Decompress time (by ticks): " + timeConsume.Ticks); + + return destms.ToArray(); + } + + /// + /// Public key + /// + private static byte[] IV = { + (byte)'m', + (byte)'s', + (byte)'n', + (byte)'p', + (byte)'s', + (byte)'h', + (byte)'a', + (byte)'r', + (byte)'p', + (byte)'l', + (byte)'i', + (byte)'b', + (byte)'r', + (byte)'a', + (byte)'r', + (byte)'y' + }; + + private static byte[] Encyrpt(byte[] val, byte[] secretKey) + { + DateTime beginTime = DateTime.Now; + byte[] ret = null; + if (val != null) + { + using (RijndaelManaged rm = new RijndaelManaged()) + { + using (MemoryStream ms = new MemoryStream()) + { + using (CryptoStream cs = new CryptoStream(ms, rm.CreateEncryptor(secretKey, IV), CryptoStreamMode.Write)) + { + using (BinaryWriter bw = new BinaryWriter(cs)) + { + bw.Write(val, 0, val.Length); + bw.Flush(); + cs.FlushFinalBlock(); + ret = ms.ToArray(); + } + } + } + } + } + + TimeSpan timeConsume = DateTime.Now - beginTime; + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, " Encyrpt time (by ticks): " + timeConsume.Ticks); + + return ret; + } + + private static byte[] Decyrpt(byte[] buffer, byte[] secretKey) + { + DateTime beginTime = DateTime.Now; + + MemoryStream ret = new MemoryStream(); + if (buffer != null) + { + using (RijndaelManaged rm = new RijndaelManaged()) + { + using (MemoryStream ms = new MemoryStream(buffer)) + { + using (CryptoStream cs = new CryptoStream(ms, rm.CreateDecryptor(secretKey, IV), CryptoStreamMode.Read)) + { + using (BinaryReader br = new BinaryReader(cs)) + { + byte[] tmp = new byte[16384]; + int length; + while ((length = br.Read(tmp, 0, tmp.Length)) > 0) + { + ret.Write(tmp, 0, length); + } + } + } + } + } + } + + TimeSpan timeConsume = DateTime.Now - beginTime; + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, " Decyrpt time (by ticks): " + timeConsume.Ticks); + return ret.ToArray(); + } + + /// + /// Compress/Encrypt the data. + /// + /// Xml data + /// + private byte[] FillFileStruct(byte[] xml) + { + byte[] ret = null; + if (xml != null) + { + switch (mclSerialization) + { + case MclSerialization.None: + ret = xml; + break; + + case MclSerialization.Compression: + byte[] compressed = Compress(xml); + ret = new byte[MclBytes.Length + compressed.Length]; + Array.Copy(MclBytes, 0, ret, 0, MclBytes.Length); + Array.Copy(compressed, 0, ret, MclBytes.Length, compressed.Length); + break; + + case MclSerialization.Cryptography: + byte[] encyrpted = Encyrpt(xml, sha256Password); + ret = new byte[MpwBytes.Length + encyrpted.Length]; + Array.Copy(MpwBytes, 0, ret, 0, MpwBytes.Length); + Array.Copy(encyrpted, 0, ret, MpwBytes.Length, encyrpted.Length); + break; + + case MclSerialization.Compression | MclSerialization.Cryptography: + byte[] compressed2 = Compress(xml); + byte[] encyrpted2 = Encyrpt(compressed2, sha256Password); + ret = new byte[McpBytes.Length + encyrpted2.Length]; + Array.Copy(McpBytes, 0, ret, 0, McpBytes.Length); + Array.Copy(encyrpted2, 0, ret, McpBytes.Length, encyrpted2.Length); + break; + } + } + return ret; + } + + /// + /// Decompress/Decyrpt the file if the serialization type is not XML. + /// + /// + private MclFileStruct GetStruct() + { + MclFileStruct mclfile = new MclFileStruct(); + if (File.Exists(fileName)) + { + MemoryStream ms = new MemoryStream(); + FileStream fs = File.Open(fileName, FileMode.Open, FileAccess.Read); + try + { + byte[] first3 = new byte[MclBytes.Length]; + if (MclBytes.Length == fs.Read(first3, 0, first3.Length)) + { + MclSerialization st = MclSerialization.None; + + if (first3[0] == MclBytes[0] && first3[1] == MclBytes[1] && first3[2] == MclBytes[2]) + { + st = MclSerialization.Compression; + } + else if (first3[0] == MpwBytes[0] && first3[1] == MpwBytes[1] && first3[2] == MpwBytes[2]) + { + st = MclSerialization.Cryptography; + } + else if (first3[0] == McpBytes[0] && first3[1] == McpBytes[1] && first3[2] == McpBytes[2]) + { + st = MclSerialization.Compression | MclSerialization.Cryptography; + } + else + { + st = MclSerialization.None; + ms.Write(first3, 0, first3.Length); + } + + int read; + byte[] tmp = new byte[16384]; + while ((read = fs.Read(tmp, 0, tmp.Length)) > 0) + { + ms.Write(tmp, 0, read); + } + + switch (st) + { + case MclSerialization.None: + mclfile.content = ms.ToArray(); + break; + + case MclSerialization.Compression: + mclfile.content = Decompress(ms.ToArray()); + break; + + case MclSerialization.Cryptography: + mclfile.content = Decyrpt(ms.ToArray(), sha256Password); + break; + + case MclSerialization.Compression | MclSerialization.Cryptography: + byte[] compressed = Decyrpt(ms.ToArray(), sha256Password); + mclfile.content = Decompress(compressed); + break; + } + } + } + catch (Exception exception) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, exception.Message, GetType().Name); + return new MclFileStruct(); + } + finally + { + fs.Close(); + ms.Close(); + } + } + return mclfile; + } + + public override string ToString() + { + return Encoding.UTF8.GetString(Content); + } + #endregion + + #region Open + + static Dictionary storage = new Dictionary(0); + static object syncObject; + static object SyncObject + { + get + { + if (syncObject == null) + { + object newobj = new object(); + Interlocked.CompareExchange(ref syncObject, newobj, null); + } + return syncObject; + } + } + + /// + /// Get the file from disk or from the storage cache. + /// + /// Full file path + /// If the file is opened for reading, file content is loaded + /// Serialization type for SAVING + /// File password + /// + /// Msnpsharp contact list file + /// This method is thread safe + public static MclFile Open(string filePath, FileAccess access, MclSerialization st, string password, bool useCache) + { + if (useCache) + { + if (storage.ContainsKey(filePath)) + { + lock (SyncObject) + { + if (storage[filePath].Refresh()) + { + storage[filePath] = new MclInfo(new MclFile(filePath, st, access, password)); + } + } + } + else + { + lock (SyncObject) + { + if (!storage.ContainsKey(filePath)) + { + storage[filePath] = new MclInfo(new MclFile(filePath, st, access, password)); + } + } + } + + return storage[filePath].File; + } + else + { + return new MclFile(filePath, st, access, password); + } + } + + #endregion + } + + #endregion +}; diff --git a/MSNPSharp/IO/MCLSerializer.cs b/MSNPSharp/IO/MCLSerializer.cs new file mode 100644 index 0000000..3497bb2 --- /dev/null +++ b/MSNPSharp/IO/MCLSerializer.cs @@ -0,0 +1,251 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Text; +using System.IO; +using System.Threading; +using System.Diagnostics; +using System.Xml.Serialization; +using System.Collections.Generic; + +namespace MSNPSharp.IO +{ + /// + /// Object serializer/deserializer class. + /// + /// + /// This class was used to save/load an object into/from a mcl file. + /// Any object needs to be serialized as a mcl file should derive from this class. + /// + [Serializable] + public abstract class MCLSerializer + { + #region Members + + [NonSerialized] + private MclSerialization serializationType; + + [NonSerialized] + private string fileName; + + [NonSerialized] + NSMessageHandler nsMessageHandler; + + [NonSerialized] + private bool useCache; + + [NonSerialized] + private object syncObject; + + private string version = "1.0"; + + #endregion + + protected MCLSerializer() + { + } + + #region Properties + + /// + /// The version of serialized object in the mcl file. + /// + [XmlAttribute("Version")] + public string Version + { + get + { + return version; + } + set + { + version = value; + } + } + + /// + /// Gets an object that can be used to synchronize access to this class. + /// + public object SyncObject + { + get + { + if (syncObject == null) + { + Interlocked.CompareExchange(ref syncObject, new object(), null); + } + + return syncObject; + } + } + + protected string FileName + { + get + { + return fileName; + } + set + { + fileName = value; + } + } + + protected MclSerialization SerializationType + { + get + { + return serializationType; + } + set + { + serializationType = value; + } + } + + protected NSMessageHandler NSMessageHandler + { + get + { + return nsMessageHandler; + } + set + { + nsMessageHandler = value; + } + } + + protected bool UseCache + { + get + { + return useCache; + } + set + { + useCache = value; + } + } + + #endregion + + #region Methods + + /// + /// Serialize and save the class into a file. + /// + public virtual void Save() + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Saving underlying data...", "<" + GetType() + ">"); + Save(FileName); + } + + /// + /// Serialize and save the class into a file. + /// + /// + public virtual void Save(string filename) + { + SaveToMCL(filename, false); + } + + protected static MCLSerializer LoadFromFile(string filename, MclSerialization st, Type targettype, NSMessageHandler handler, bool useCache) + { + int beginTick = Environment.TickCount; + MCLSerializer ret = (MCLSerializer)Activator.CreateInstance(targettype); + + if (Settings.NoSave == false && File.Exists(filename)) + { + MclFile file = MclFile.Open(filename, FileAccess.Read, st, handler.Credentials.Password, useCache); + + int deserializeTick = Environment.TickCount; + + if (file.Content != null) + { + using (MemoryStream ms = new MemoryStream(file.Content)) + { + try + { + ret = (MCLSerializer)new XmlSerializer(targettype).Deserialize(ms); + } + catch (Exception) + { + // Deserialize error: XML struct changed, so create a empty mcl serializer. + ret = (MCLSerializer)Activator.CreateInstance(targettype); + } + } + } + + int deserializeTickConsume = Environment.TickCount - deserializeTick; + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "<" + ret.GetType().ToString() + "> Deserialize time (by ticks): " + deserializeTickConsume); + } + + ret.SerializationType = st; + ret.FileName = filename; + ret.NSMessageHandler = handler; + ret.UseCache = useCache; + + int tickConsume = Environment.TickCount - beginTick; + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "<" + ret.GetType().ToString() + "> Total loading time (by ticks): " + tickConsume + "\r\n"); + + return ret; + } + + + + private void SaveToMCL(string filename, bool saveToHiddenFile) + { + int beginTime = Environment.TickCount; + if (!Settings.NoSave) + { + int serializeBegin = Environment.TickCount; + XmlSerializer ser = new XmlSerializer(this.GetType()); + MemoryStream ms = new MemoryStream(); + ser.Serialize(ms, this); + + int serializeTickConsume = Environment.TickCount - serializeBegin; + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "<" + this.GetType().ToString() + "> serialize time (by ticks): " + serializeTickConsume); + + MclFile file = MclFile.Open(filename, FileAccess.Write, SerializationType, NSMessageHandler.Credentials.Password, UseCache); + file.Content = ms.ToArray(); + file.Save(filename, saveToHiddenFile); + ms.Close(); + } + + int tickConsume = Environment.TickCount - beginTime; + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "<" + this.GetType().ToString() + "> Total saving time (by ticks): " + tickConsume + "\r\n"); + } + + #endregion + } +}; diff --git a/MSNPSharp/IO/SerializableClasses.cs b/MSNPSharp/IO/SerializableClasses.cs new file mode 100644 index 0000000..8c5c586 --- /dev/null +++ b/MSNPSharp/IO/SerializableClasses.cs @@ -0,0 +1,448 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Xml; +using System.Text; +using System.Collections.Generic; + +namespace MSNPSharp.IO +{ + using MSNPSharp.MSNWS.MSNABSharingService; + using MSNPSharp.Core; + + #region Service + + /// + /// Membership service + /// + [Serializable] + public class Service : ICloneable, IComparable, IComparable + { + private int id; + public int Id + { + get + { + return id; + } + set + { + id = value; + } + } + + private string serviceType; + public string ServiceType + { + get + { + return serviceType; + } + set + { + serviceType = value; + } + } + + private string lastChange; + public string LastChange + { + get + { + return lastChange; + } + set + { + lastChange = value; + } + } + + private string foreignId; + public string ForeignId + { + get + { + return foreignId; + } + set + { + foreignId = value; + } + } + + public Service() + { + } + + public Service(Service copy) + { + Id = copy.Id; + ServiceType = copy.ServiceType; + LastChange = copy.LastChange; + ForeignId = String.Copy(copy.ForeignId); + } + + public override string ToString() + { + return Convert.ToString(ServiceType); + } + + public static bool operator ==(Service svc1, Service svc2) + { + if (((object)svc1) == null && ((object)svc2) == null) + return true; + + if (((object)svc1) == null || ((object)svc2) == null) + return false; + + return svc1.GetHashCode() == svc2.GetHashCode(); + } + + public static bool operator !=(Service svc1, Service svc2) + { + return !(svc1 == svc2); + } + + public override bool Equals(object obj) + { + if (obj == null || obj.GetType() != GetType()) + return false; + + if (ReferenceEquals(this, obj)) + return true; + + return obj.GetHashCode() == GetHashCode(); + } + + public override int GetHashCode() + { + return id; + } + + #region ICloneable Members + + public object Clone() + { + return new Service(this); + } + + #endregion + + #region IComparable Members + + public int CompareTo(object obj) + { + if (obj == null) + { + return 1; + } + + if (!(obj is Service)) + { + throw new ArgumentException("obj"); + } + + return CompareTo((Service)obj); + } + + #endregion + + #region IComparable Members + + public int CompareTo(Service other) + { + if (other == null) + { + return 1; + } + + return DateTime.Compare(WebServiceDateTimeConverter.ConvertToDateTime(LastChange), WebServiceDateTimeConverter.ConvertToDateTime(other.LastChange)); + } + + #endregion + } + + #endregion + + #region ServiceMembership + [Serializable] + public class ServiceMembership + { + private Service service; + private SerializableDictionary> memberships = new SerializableDictionary>(0); + + public Service Service + { + get + { + return service; + } + set + { + service = value; + } + } + + public SerializableDictionary> Memberships + { + get + { + return memberships; + } + set + { + memberships = value; + } + } + + public ServiceMembership() + { + } + + public ServiceMembership(Service srvc) + { + service = srvc; + } + } + #endregion + + #region Owner properties + + /// + /// Base class for profile resource + /// + [Serializable] + public class ProfileResource + { + private string dateModified; + private string resourceID; + + /// + /// Last modify time of the resource + /// + public string DateModified + { + get + { + return dateModified; + } + set + { + dateModified = value; + } + } + + /// + /// Identifier of the resource + /// + public string ResourceID + { + get + { + return resourceID; + } + set + { + resourceID = value; + } + } + } + + /// + /// Owner's photo resource in profile + /// + [Serializable] + public class ProfilePhoto : ProfileResource + { + private string preAthURL; + private string name = string.Empty; + private SerializableMemoryStream displayImage; + + public string PreAthURL + { + get + { + return preAthURL; + } + set + { + preAthURL = value; + } + } + + public string Name + { + get + { + return name; + } + set + { + name = value; + } + } + + public SerializableMemoryStream DisplayImage + { + get + { + return displayImage; + } + set + { + displayImage = value; + } + } + } + + /// + /// Owner profile + /// + [Serializable] + public class OwnerProfile : ProfileResource + { + private string displayName = string.Empty; + private string personalMessage = string.Empty; + private ProfilePhoto photo = new ProfilePhoto(); + private bool hasExpressionProfile = true; + private ProfileResource expressionProfile = new ProfileResource(); + + public ProfileResource ExpressionProfile + { + get { return expressionProfile; } + set { expressionProfile = value; } + } + + /// + /// Whether the profile owner is using hotmail or live account for msn login. + /// + public bool HasExpressionProfile + { + get + { + return hasExpressionProfile; + } + + set + { + hasExpressionProfile = value; + } + } + + /// + /// DisplayImage of owner. + /// + public ProfilePhoto Photo + { + get + { + return photo; + } + set + { + photo = value; + } + } + + /// + /// DisplayName of owner + /// + public string DisplayName + { + get + { + return displayName; + } + set + { + displayName = value; + } + } + + /// + /// Personal description of owner. + /// + public string PersonalMessage + { + get + { + return personalMessage; + } + set + { + personalMessage = value; + } + } + + + } + + [Serializable()] + public class CircleInfo + { + private string memberRole = MSNPSharp.MemberRole.Allow; + private ContactType circleMember = null; + private CircleInverseInfoType circleResultInfo = null; + + public string MemberRole + { + get { return memberRole; } + set { memberRole = value; } + } + + public CircleInverseInfoType CircleResultInfo + { + get { return circleResultInfo; } + set { circleResultInfo = value; } + } + + + public ContactType CircleMember + { + get { return circleMember; } + set { circleMember = value; } + } + + public CircleInfo() + { + } + + + public CircleInfo(ContactType contact, CircleInverseInfoType circle) + { + CircleMember = contact; + CircleResultInfo = circle; + } + } + #endregion +}; diff --git a/MSNPSharp/IO/SerializableDictionary.cs b/MSNPSharp/IO/SerializableDictionary.cs new file mode 100644 index 0000000..9c27d9e --- /dev/null +++ b/MSNPSharp/IO/SerializableDictionary.cs @@ -0,0 +1,200 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml.Serialization; +using System.Runtime.Serialization; + +namespace MSNPSharp.IO +{ + /// + /// Serializable Dictionary + /// + /// Key type + /// Value type + [XmlRoot("Dictionary"), Serializable] + public class SerializableDictionary + : Dictionary, IXmlSerializable + { + + private object syncObject = new object(); + + public object SyncObject + { + get { return syncObject; } + } + + #region .ctor + + public SerializableDictionary() + : base() + { + + } + + public SerializableDictionary(IDictionary dictionary) + : base(dictionary) + { + + } + + + public SerializableDictionary(IEqualityComparer comparer) + : base(comparer) + { + } + + + public SerializableDictionary(int capacity) + : base(capacity) + { + + } + + public SerializableDictionary(int capacity, IEqualityComparer comparer) + : base(capacity, comparer) + { + + } + + protected SerializableDictionary(SerializationInfo info, StreamingContext context) + : base(info, context) + { + + } + + #endregion + + public new bool ContainsKey(TKey key) + { + lock (SyncObject) + { + return base.ContainsKey(key); + } + } + + public new bool ContainsValue(TValue val) + { + lock (SyncObject) + { + return base.ContainsValue(val); + } + } + + public new void Add(TKey key, TValue value) + { + lock (SyncObject) + { + base.Add(key, value); + } + } + + public new TValue this[TKey key] + { + get + { + lock(SyncObject) + { + return base[key]; + } + } + + set + { + lock (SyncObject) + { + base[key] = value; + } + } + } + + #region IXmlSerializable Members + public System.Xml.Schema.XmlSchema GetSchema() + { + return null; + } + + public void ReadXml(System.Xml.XmlReader reader) + { + + XmlSerializer keySerializer = new XmlSerializer(typeof(TKey)); + XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue)); + bool wasEmpty = reader.IsEmptyElement; + reader.Read(); + + if (wasEmpty) + return; + while (reader.NodeType != System.Xml.XmlNodeType.EndElement) + { + reader.ReadStartElement("item"); + reader.ReadStartElement("key"); + TKey key = (TKey)keySerializer.Deserialize(reader); + reader.ReadEndElement(); + reader.ReadStartElement("value"); + TValue value = (TValue)valueSerializer.Deserialize(reader); + reader.ReadEndElement(); + this.Add(key, value); + reader.ReadEndElement(); + reader.MoveToContent(); + + } + reader.ReadEndElement(); + + } + + public void WriteXml(System.Xml.XmlWriter writer) + { + + XmlSerializer keySerializer = new XmlSerializer(typeof(TKey)); + XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue)); + foreach (TKey key in this.Keys) + { + writer.WriteStartElement("item"); + writer.WriteStartElement("key"); + keySerializer.Serialize(writer, key); + writer.WriteEndElement(); + writer.WriteStartElement("value"); + TValue value = this[key]; + valueSerializer.Serialize(writer, value); + writer.WriteEndElement(); + writer.WriteEndElement(); + } + + } + + #endregion + + } + +} diff --git a/MSNPSharp/IO/SerializableMemoryStream.cs b/MSNPSharp/IO/SerializableMemoryStream.cs new file mode 100644 index 0000000..37066ba --- /dev/null +++ b/MSNPSharp/IO/SerializableMemoryStream.cs @@ -0,0 +1,103 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Xml; +using System.Text; +using System.Drawing; +using System.Xml.Schema; +using System.Xml.Serialization; +using System.Collections.Generic; + +namespace MSNPSharp.IO +{ + /// + /// Serializable MemoryStream + /// + [Serializable] + [XmlRoot("Stream")] + public class SerializableMemoryStream : MemoryStream, IXmlSerializable + { + #region IXmlSerializable Members + + public XmlSchema GetSchema() + { + return null; + } + + public void ReadXml(XmlReader reader) + { + if (reader.IsEmptyElement) + return; + + reader.Read(); + byte[] byt = (byte[])new XmlSerializer(typeof(byte[])).Deserialize(reader); + reader.ReadEndElement(); + + Write(byt, 0, byt.Length); + Flush(); + } + + public void WriteXml(XmlWriter writer) + { + byte[] data = ToArray(); + if (data != null) + { + new XmlSerializer(typeof(byte[])).Serialize(writer, data); + } + } + + public Image ToImage() + { + return Image.FromStream(this); + } + + public static SerializableMemoryStream FromImage(Image image) + { + SerializableMemoryStream ret = new SerializableMemoryStream(); + image.Save(ret, image.RawFormat); + return ret; + } + + public static explicit operator Image(SerializableMemoryStream ms) + { + return ms.ToImage(); + } + + public static explicit operator SerializableMemoryStream(Image image) + { + return SerializableMemoryStream.FromImage(image); + } + #endregion + } +}; diff --git a/MSNPSharp/IO/XMLContactList.cs b/MSNPSharp/IO/XMLContactList.cs new file mode 100644 index 0000000..1f96e1e --- /dev/null +++ b/MSNPSharp/IO/XMLContactList.cs @@ -0,0 +1,2733 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Xml; +using System.Diagnostics; +using System.Globalization; +using System.Xml.Serialization; +using System.Collections.Generic; + +namespace MSNPSharp.IO +{ + using MSNPSharp.MSNWS.MSNABSharingService; + using MSNPSharp.Core; + + /// + /// ContactList file maintainer + /// + [Serializable] + [XmlRoot("ContactList")] + public class XMLContactList : MCLSerializer + { + [NonSerialized] + private bool initialized = false; + + [NonSerialized] + private int requestCircleCount = 0; + + public static XMLContactList LoadFromFile(string filename, MclSerialization st, NSMessageHandler handler, bool useCache) + { + return (XMLContactList)LoadFromFile(filename, st, typeof(XMLContactList), handler, useCache); + } + + /// + /// Initialize contacts from mcl file. Creates contacts based on MemberShipList, Groups, CircleResults and AddressbookContacts. + /// MemberShipList, Groups, CircleResults and AddressbookContacts is pure clean and no contains DELTAS... + /// So, member.Deleted is not valid here... + /// + internal void Initialize() + { + if (initialized) + return; + + initialized = true; + + #region Restore Memberships + + SerializableDictionary> ms = + SelectTargetMemberships(ServiceFilterType.Messenger); + + if (ms != null) + { + foreach (string role in ms.Keys) + { + MSNLists msnlist = NSMessageHandler.ContactService.GetMSNList(role); + foreach (BaseMember bm in ms[role].Values) + { + long cid = 0; + string account = null; + ClientType type = ClientType.None; + + if (bm is PassportMember) + { + type = ClientType.PassportMember; + PassportMember pm = (PassportMember)bm; + if (!pm.IsPassportNameHidden) + { + account = pm.PassportName; + } + cid = Convert.ToInt64(pm.CID); + } + else if (bm is EmailMember) + { + type = ClientType.EmailMember; + account = ((EmailMember)bm).Email; + } + else if (bm is PhoneMember) + { + type = ClientType.PhoneMember; + account = ((PhoneMember)bm).PhoneNumber; + } + + if (account != null && type != ClientType.None) + { + string displayname = bm.DisplayName == null ? account : bm.DisplayName; + Contact contact = NSMessageHandler.ContactList.GetContact(account, displayname, type); + contact.CID = cid; + contact.Lists |= msnlist; + } + } + } + } + + #endregion + + #region Restore Groups + + foreach (GroupType group in Groups.Values) + { + NSMessageHandler.ContactGroups.AddGroup(new ContactGroup(group.groupInfo.name, group.groupId, NSMessageHandler, group.groupInfo.IsFavorite)); + } + + #endregion + + #region Restore CID contact table + + foreach (string abId in AddressbookContacts.Keys) + { + ContactType[] contactList = new ContactType[AddressbookContacts[abId].Count]; + + AddressbookContacts[abId].Values.CopyTo(contactList, 0); + SaveContactTable(contactList); + } + + #endregion + + #region Restore Circles + + string[] abIds = FilterWLConnections(new List(CircleResults.Keys), RelationshipState.Accepted); + RestoreCircles(abIds, RelationshipState.Accepted); + abIds = FilterWLConnections(new List(CircleResults.Keys), RelationshipState.WaitingResponse); + RestoreCircles(abIds, RelationshipState.WaitingResponse); + + #endregion + + #region Restore default addressbook + + if (AddressbookContacts.ContainsKey(WebServiceConstants.MessengerIndividualAddressBookId)) + { + SerializableDictionary defaultPage = AddressbookContacts[WebServiceConstants.MessengerIndividualAddressBookId]; + foreach (ContactType contactType in defaultPage.Values) + { + Contact tmpContact; + ReturnState updateResult = UpdateContact(contactType, out tmpContact); //Restore contacts. + if ((updateResult & ReturnState.UpdateError) != ReturnState.None) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[Initialize Error]: update contact error."); + } + } + } + + #endregion + + } + + private bool IsContactTableEmpty() + { + lock (contactTable) + return contactTable.Count == 0; + } + + private bool IsPendingCreateConfirmCircle(string abId) + { + lock (PendingCreateCircleList) + return PendingCreateCircleList.ContainsKey(new Guid(abId)); + } + + private bool IsPendingCreateConfirmCircle(Guid abId) + { + lock (PendingCreateCircleList) + return PendingCreateCircleList.ContainsKey(abId); + } + + #region New MembershipList + + private SerializableDictionary mslist = new SerializableDictionary(0); + public SerializableDictionary MembershipList + { + get + { + return mslist; + } + set + { + mslist = value; + } + } + + public string MembershipLastChange + { + get + { + if (MembershipList.Keys.Count == 0) + return WebServiceConstants.ZeroTime; + + List services = new List(); + foreach (string sft in MembershipList.Keys) + services.Add(new Service(MembershipList[sft].Service)); + + services.Sort(); + return services[services.Count - 1].LastChange; + } + } + + internal Service SelectTargetService(string type) + { + if (MembershipList.ContainsKey(type)) + return MembershipList[type].Service; + + return null; + } + + internal SerializableDictionary> SelectTargetMemberships(string serviceFilterType) + { + if (MembershipList.ContainsKey(serviceFilterType)) + return MembershipList[serviceFilterType].Memberships; + + return null; + } + + /// + /// Add a member to the underlying membership data structure. + /// + /// + /// + /// + /// + /// + /// + /// Since AllowList and BlockList are mutally exclusive, adding a member to AllowList will lead to the remove of BlockList, revese is as the same. + internal void AddMemberhip(string servicetype, string account, ClientType type, string memberrole, BaseMember member, Scenario scene) + { + lock(SyncObject) + { + SerializableDictionary> ms = SelectTargetMemberships(servicetype); + if (ms != null) + { + if (!ms.ContainsKey(memberrole)) + ms.Add(memberrole, new SerializableDictionary(0)); + + ms[memberrole][Contact.MakeHash(account, type, WebServiceConstants.MessengerIndividualAddressBookId)] = member; + } + + switch (scene) + { + case Scenario.DeltaRequest: + if (memberrole == MemberRole.Allow) + { + RemoveMemberhip(servicetype, account, type, MemberRole.Block, Scenario.InternalCall); + } + + if (memberrole == MemberRole.Block) + { + RemoveMemberhip(servicetype, account, type, MemberRole.Allow, Scenario.InternalCall); + } + + break; + } + } + } + + internal void RemoveMemberhip(string servicetype, string account, ClientType type, string memberrole, Scenario scene) + { + lock(SyncObject) + { + SerializableDictionary> ms = SelectTargetMemberships(servicetype); + if (ms != null) + { + string hash = Contact.MakeHash(account, type, WebServiceConstants.MessengerIndividualAddressBookId); + if (ms.ContainsKey(memberrole) && ms[memberrole].ContainsKey(hash)) + { + ms[memberrole].Remove(hash); + } + } + } + } + + /// + /// Try to remove a contact from a specific addressbook. + /// + /// The specific addressbook identifier. + /// The contact identifier. + /// If the contact exists and removed successfully, return true, else return false. + internal bool RemoveContactFromAddressBook(Guid abId, Guid contactId) + { + return RemoveContactFromAddressBook(abId.ToString("D"), contactId); + } + + /// + /// Try to remove a contact from a specific addressbook. + /// + /// The specific addressbook identifier. + /// The contact identifier. + /// If the contact exists and removed successfully, return true, else return false. + internal bool RemoveContactFromAddressBook(string abId, Guid contactId) + { + lock(SyncObject) + { + string lowerId = abId.ToLowerInvariant(); + lock (AddressbookContacts) + { + if (AddressbookContacts.ContainsKey(lowerId)) + { + if (AddressbookContacts[lowerId].ContainsKey(contactId)) + { + return AddressbookContacts[lowerId].Remove(contactId); + } + } + } + + return false; + } + } + + + private bool RemoveContactFromContactTable(long CID) + { + lock (contactTable) + return contactTable.Remove(CID); + } + + /// + /// Remove an item in AddressBooksInfo property by giving an addressbook Id. + /// + /// + /// + private bool RemoveAddressBookInfo(string abId) + { + + lock (AddressBooksInfo) + return AddressBooksInfo.Remove(abId.ToLowerInvariant()); + } + + /// + /// Remove an item from AddressbookContacts property. + /// + /// The addressbook page of a specified contact page. + /// + private bool RemoveAddressBookContatPage(string abId) + { + lock (AddressbookContacts) + { + return AddressbookContacts.Remove(abId.ToLowerInvariant()); + } + } + + /// + /// Add or update a contact in the specific address book. + /// + /// The identifier of addressbook. + /// The contact to be added/updated. + /// If the contact added to the addressbook, returen true, if the contact is updated (not add), return false. + internal bool SetContactToAddressBookContactPage(string abId, ContactType contact) + { + lock(SyncObject) + { + string lowerId = abId.ToLowerInvariant(); + bool returnval = false; + + lock (AddressbookContacts) + { + if (!AddressbookContacts.ContainsKey(lowerId)) + { + AddressbookContacts.Add(lowerId, new SerializableDictionary()); + returnval = true; + } + + AddressbookContacts[lowerId][new Guid(contact.contactId)] = contact; + } + + return returnval; + } + } + + private bool SetAddressBookInfoToABInfoList(string abId, ABFindContactsPagedResultTypeAB abInfo) + { + string lowerId = abId.ToLowerInvariant(); + if (AddressBooksInfo == null) + return false; + + lock (AddressBooksInfo) + AddressBooksInfo[lowerId] = abInfo; + return true; + } + + + private bool HasContact(long CID) + { + lock (contactTable) + return contactTable.ContainsKey(CID); + } + + private bool HasWLConnection(string abId) + { + lock (CircleResults) + return CircleResults.ContainsKey(abId); + } + + /// + /// Check whether we've saved the specified addressbook. + /// + /// + /// + private bool HasAddressBook(string abId) + { + string lowerId = abId.ToLowerInvariant(); + if (AddressBooksInfo == null) + return false; + + lock (AddressBooksInfo) + return AddressBooksInfo.ContainsKey(lowerId); + } + + /// + /// Check whether the specific contact page exist. + /// + /// The addressbook identifier of a specific contact page. + /// + private bool HasAddressBookContactPage(string abId) + { + string lowerId = abId.ToLowerInvariant(); + if (AddressbookContacts == null) + return false; + + bool returnValue = false; + + lock (AddressbookContacts) + { + if (AddressbookContacts.ContainsKey(lowerId)) + { + if (AddressbookContacts[lowerId] != null) + { + returnValue = true; + } + } + } + + return returnValue; + } + + internal bool HasContact(string abId, Guid contactId) + { + string lowerId = abId.ToLowerInvariant(); + lock (AddressbookContacts) + { + if (!AddressbookContacts.ContainsKey(lowerId)) + return false; + + return AddressbookContacts[lowerId].ContainsKey(contactId); + } + } + + private bool HasMemberhip(string servicetype, string account, ClientType type, string memberrole) + { + SerializableDictionary> ms = SelectTargetMemberships(servicetype); + return (ms != null) && ms.ContainsKey(memberrole) && ms[memberrole].ContainsKey(Contact.MakeHash(account, type, WebServiceConstants.MessengerIndividualAddressBookId)); + } + + /// + /// Get a basemember from membership list. + /// + /// + /// + /// + /// + /// If the member not exist, return null. + public BaseMember SelectBaseMember(string servicetype, string account, ClientType type, string memberrole) + { + string hash = Contact.MakeHash(account, type, WebServiceConstants.MessengerIndividualAddressBookId); + SerializableDictionary> ms = SelectTargetMemberships(servicetype); + if ((ms != null) && ms.ContainsKey(memberrole) && ms[memberrole].ContainsKey(hash)) + { + return ms[memberrole][hash]; + } + return null; + } + + /// + /// Get a contact from a specific addressbook by providing the addressbook identifier and contact identifier. + /// + /// The addressbook identifier. + /// The contactidentifier. + /// If the contact exist, return the contact object, else return null. + internal ContactType SelectContactFromAddressBook(string abId, Guid contactId) + { + string lowerId = abId.ToLowerInvariant(); + if (!HasContact(abId, contactId)) + return null; + return AddressbookContacts[lowerId][contactId]; + } + + public virtual void Add( + Dictionary>> range) + { + lock(SyncObject) + { + foreach (Service svc in range.Keys) + { + foreach (string role in range[svc].Keys) + { + foreach (string hash in range[svc][role].Keys) + { + if (!mslist.ContainsKey(svc.ServiceType)) + mslist.Add(svc.ServiceType, new ServiceMembership(svc)); + + if (!mslist[svc.ServiceType].Memberships.ContainsKey(role)) + mslist[svc.ServiceType].Memberships.Add(role, new SerializableDictionary(0)); + + if (mslist[svc.ServiceType].Memberships[role].ContainsKey(hash)) + { + if (/* mslist[svc.ServiceType].Memberships[role][hash].LastChangedSpecified + && */ + WebServiceDateTimeConverter.ConvertToDateTime(mslist[svc.ServiceType].Memberships[role][hash].LastChanged).CompareTo( + WebServiceDateTimeConverter.ConvertToDateTime(range[svc][role][hash].LastChanged)) <= 0) + { + mslist[svc.ServiceType].Memberships[role][hash] = range[svc][role][hash]; + } + } + else + { + mslist[svc.ServiceType].Memberships[role].Add(hash, range[svc][role][hash]); + } + } + } + } + } + } + + /// + /// Get the hidden representative's CID by providing addressbook Id from the inverse connection list. + /// + /// + /// + private CircleInverseInfoType SelectWLConnection(string abId) + { + if (string.IsNullOrEmpty(abId)) + return null; + + string lowerId = abId.ToLowerInvariant(); + if (!HasWLConnection(lowerId)) + return null; + + lock (CircleResults) + return CircleResults[lowerId]; + + } + + private string[] SelectWLConnection(List abIds, RelationshipState state) + { + List results = new List(0); + + lock (CircleResults) + { + foreach (string abId in abIds) + { + if (HasWLConnection(abId)) + { + if (state == RelationshipState.None) + { + results.Add(abId); + } + else + { + if (CircleResults[abId.ToLowerInvariant()].PersonalInfo.MembershipInfo.CirclePersonalMembership.State == state.ToString()) + results.Add(abId); + } + + } + } + } + + return results.ToArray(); + } + + private string[] FilterWLConnections(List abIds, RelationshipState state) + { + List returnValues = new List(0); + + + foreach (string abId in abIds) + { + string lowerId = abId.ToLowerInvariant(); + if (CircleResults.ContainsKey(lowerId)) + { + CircleInverseInfoType inverseInfo = CircleResults[lowerId]; + if (inverseInfo.PersonalInfo.MembershipInfo.CirclePersonalMembership.State == state.ToString()) + returnValues.Add(abId); + } + } + + return returnValues.ToArray(); + } + + private CircleInverseInfoType SelectCircleInverseInfo(string abId) + { + if (string.IsNullOrEmpty(abId)) + return null; + + abId = abId.ToLowerInvariant(); + + lock (CircleResults) + { + if (!CircleResults.ContainsKey(abId)) + return null; + return CircleResults[abId]; + } + } + + /// + /// Get a hidden representative for a addressbook by CID. + /// + /// + /// + private ContactType SelecteContact(long CID) + { + if (!HasContact(CID)) + { + return null; + } + + lock (contactTable) + return contactTable[CID]; + } + + public XMLContactList Merge(FindMembershipResultType findMembership) + { + lock(SyncObject) + { + Initialize(); + + // Process new FindMemberships (deltas) + if (null != findMembership && null != findMembership.Services) + { + foreach (ServiceType serviceType in findMembership.Services) + { + Service oldService = SelectTargetService(serviceType.Info.Handle.Type); + + if (oldService == null || + WebServiceDateTimeConverter.ConvertToDateTime(oldService.LastChange) + < WebServiceDateTimeConverter.ConvertToDateTime(serviceType.LastChange)) + { + if (serviceType.Deleted) + { + if (MembershipList.ContainsKey(serviceType.Info.Handle.Type)) + { + MembershipList.Remove(serviceType.Info.Handle.Type); + } + } + else + { + Service updatedService = new Service(); + updatedService.Id = int.Parse(serviceType.Info.Handle.Id); + updatedService.ServiceType = serviceType.Info.Handle.Type; + updatedService.LastChange = serviceType.LastChange; + updatedService.ForeignId = serviceType.Info.Handle.ForeignId; + + if (oldService == null) + { + MembershipList.Add(updatedService.ServiceType, new ServiceMembership(updatedService)); + } + + if (null != serviceType.Memberships) + { + if (ServiceFilterType.Messenger == serviceType.Info.Handle.Type) + { + + ProcessMessengerServiceMemberships(serviceType, ref updatedService); + } + else + { + ProcessOtherMemberships(serviceType, ref updatedService); + } + + } + + // Update service.LastChange + MembershipList[updatedService.ServiceType].Service = updatedService; + } + } + } + } + + return this; + } + } + + private void ProcessMessengerServiceMemberships(ServiceType messengerService, ref Service messengerServiceClone) + { + #region Messenger Service memberhips + + foreach (Membership membership in messengerService.Memberships) + { + if (null != membership.Members) + { + string memberrole = membership.MemberRole; + List members = new List(membership.Members); + members.Sort(CompareBaseMembers); + + foreach (BaseMember bm in members) + { + long cid = 0; + string account = null; + ClientType type = ClientType.None; + + if (bm is PassportMember) + { + type = ClientType.PassportMember; + PassportMember pm = bm as PassportMember; + if (!pm.IsPassportNameHidden) + { + account = pm.PassportName; + } + cid = Convert.ToInt64(pm.CID); + } + else if (bm is EmailMember) + { + type = ClientType.EmailMember; + account = ((EmailMember)bm).Email; + } + else if (bm is PhoneMember) + { + type = ClientType.PhoneMember; + account = ((PhoneMember)bm).PhoneNumber; + } + else if (bm is CircleMember) + { + type = ClientType.CircleMember; + account = ((CircleMember)bm).CircleId; + if (!circlesMembership.ContainsKey(memberrole)) + { + circlesMembership.Add(memberrole, new List(0)); + } + circlesMembership[memberrole].Add(bm as CircleMember); + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, messengerService.Info.Handle.Type + " Membership " + bm.GetType().ToString() + ": " + memberrole + ":" + account); + } + + if (account != null && type != ClientType.None) + { + account = account.ToLowerInvariant(); + MSNLists msnlist = NSMessageHandler.ContactService.GetMSNList(memberrole); + + if (bm.Deleted) + { + #region Members deleted in other clients. + + if (type != ClientType.CircleMember) + { + if (HasMemberhip(messengerServiceClone.ServiceType, account, type, memberrole) && + WebServiceDateTimeConverter.ConvertToDateTime(MembershipList[messengerServiceClone.ServiceType].Memberships[memberrole][Contact.MakeHash(account, type, WebServiceConstants.MessengerIndividualAddressBookId)].LastChanged) + < WebServiceDateTimeConverter.ConvertToDateTime(bm.LastChanged)) + { + RemoveMemberhip(messengerServiceClone.ServiceType, account, type, memberrole, Scenario.DeltaRequest); + } + + if (NSMessageHandler.ContactList.HasContact(account, type)) + { + Contact contact = NSMessageHandler.ContactList.GetContact(account, type); + contact.CID = cid; + if (contact.HasLists(msnlist)) + { + contact.RemoveFromList(msnlist); + + // Fire ReverseRemoved + if (msnlist == MSNLists.ReverseList) + { + NSMessageHandler.ContactService.OnReverseRemoved(new ContactEventArgs(contact)); + } + + // Send a list remove event + NSMessageHandler.ContactService.OnContactRemoved(new ListMutateEventArgs(contact, msnlist)); + } + } + } + + #endregion + + } + else + { + #region Newly added memberships. + + if (type != ClientType.CircleMember) + { + + if (false == MembershipList[messengerServiceClone.ServiceType].Memberships.ContainsKey(memberrole) || + /*new*/ false == MembershipList[messengerServiceClone.ServiceType].Memberships[memberrole].ContainsKey(Contact.MakeHash(account, type, WebServiceConstants.MessengerIndividualAddressBookId)) || + /*probably membershipid=0*/ WebServiceDateTimeConverter.ConvertToDateTime(bm.LastChanged) + > WebServiceDateTimeConverter.ConvertToDateTime(MembershipList[messengerServiceClone.ServiceType].Memberships[memberrole][Contact.MakeHash(account, type, WebServiceConstants.MessengerIndividualAddressBookId)].LastChanged)) + { + AddMemberhip(messengerServiceClone.ServiceType, account, type, memberrole, bm, Scenario.DeltaRequest); + } + + string displayname = bm.DisplayName == null ? account : bm.DisplayName; + Contact contact = NSMessageHandler.ContactList.GetContact(account, displayname, type); + contact.CID = cid; + + if (!contact.HasLists(msnlist)) + { + contact.AddToList(msnlist); + contact.Lists ^= Contact.GetConflictLists(contact.Lists, msnlist); + NSMessageHandler.ContactService.OnContactAdded(new ListMutateEventArgs(contact, msnlist)); + + // Added by other place, this place hasn't synchronized this contact yet. + if (contact.OnForwardList && contact.OnPendingList) + { + contact.OnPendingList = false; + } + // At this phase, we requested all memberships including pending. + else if (contact.OnPendingList || + (contact.OnReverseList && !contact.OnAllowedList && !contact.OnBlockedList)) + { + NSMessageHandler.ContactService.OnReverseAdded(new ContactEventArgs(contact)); + + } + } + } + + #endregion + } + } + } + } + } + + #endregion + } + + private void ProcessOtherMemberships(ServiceType service, ref Service serviceClone) + { + foreach (Membership membership in service.Memberships) + { + if (null != membership.Members) + { + string memberrole = membership.MemberRole; + List members = new List(membership.Members); + members.Sort(CompareBaseMembers); + foreach (BaseMember bm in members) + { + string account = null; + ClientType type = ClientType.None; + + switch (bm.Type) + { + case MembershipType.Passport: + type = ClientType.PassportMember; + PassportMember pm = bm as PassportMember; + if (!pm.IsPassportNameHidden) + { + account = pm.PassportName; + } + break; + + case MembershipType.Email: + type = ClientType.EmailMember; + account = ((EmailMember)bm).Email; + break; + + case MembershipType.Phone: + type = ClientType.PhoneMember; + account = ((PhoneMember)bm).PhoneNumber; + break; + + case MembershipType.Role: + case MembershipType.Service: + case MembershipType.Everyone: + case MembershipType.Partner: + account = bm.Type + "/" + bm.MembershipId; + break; + + case MembershipType.Domain: + account = ((DomainMember)bm).DomainName; + break; + + case MembershipType.Circle: + type = ClientType.CircleMember; + account = ((CircleMember)bm).CircleId; + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, service.Info.Handle.Type + " Membership " + bm.GetType().ToString() + ": " + memberrole + ":" + account); + break; + } + + if (account != null) + { + if (bm.Deleted) + { + RemoveMemberhip(serviceClone.ServiceType, account, type, memberrole, Scenario.DeltaRequest); + } + else + { + AddMemberhip(serviceClone.ServiceType, account, type, memberrole, bm, Scenario.DeltaRequest); + } + } + } + } + } + } + + private static int CompareBaseMembers(BaseMember x, BaseMember y) + { + return x.LastChanged.CompareTo(y.LastChanged); + } + + + #endregion + + #region Addressbook + + SerializableDictionary abInfos = new SerializableDictionary(); + SerializableDictionary myproperties = new SerializableDictionary(0); + SerializableDictionary groups = new SerializableDictionary(0); + SerializableDictionary> abcontacts = new SerializableDictionary>(0); + + SerializableDictionary circleResults = new SerializableDictionary(0); + SerializableDictionary wlConnections = new SerializableDictionary(0); + + SerializableDictionary hiddenRepresentatives = new SerializableDictionary(0); + SerializableDictionary> circlesMembership = new SerializableDictionary>(0); + + [NonSerialized] + Dictionary contactTable = new Dictionary(); + + [NonSerialized] + Dictionary wlInverseConnections = new Dictionary(); + + [NonSerialized] + private CircleList pendingAcceptionCircleList; + + [NonSerialized] + Dictionary pendingCreateCircleList = new Dictionary(); + + /// + /// Circles created by the library and waiting server's confirm. + /// + internal Dictionary PendingCreateCircleList + { + get + { + return pendingCreateCircleList; + } + } + + /// + /// A collection of all circles which are pending acception. + /// + internal CircleList PendingAcceptionCircleList + { + get + { + if (pendingAcceptionCircleList == null && NSMessageHandler != null) + pendingAcceptionCircleList = new CircleList(NSMessageHandler); + + return pendingAcceptionCircleList; + } + } + + + /// + /// The relationship mapping from addressbook Ids to hidden represtative's CIDs. + /// + internal Dictionary WLInverseConnections + { + get + { + return wlInverseConnections; + } + } + + public SerializableDictionary HiddenRepresentatives + { + get + { + return hiddenRepresentatives; + } + set + { + hiddenRepresentatives = value; + } + } + + /// + /// The relationship mapping from hidden represtative's CIDs to addressbook Ids. + /// + public SerializableDictionary WLConnections + { + get + { + return wlConnections; + } + + set + { + wlConnections = value; + } + } + + public SerializableDictionary CircleResults + { + get + { + return circleResults; + } + set + { + circleResults = value; + } + } + + [XmlElement("AddressBooksInfo")] + public SerializableDictionary AddressBooksInfo + { + get + { + return abInfos; + } + + set + { + abInfos = value; + } + } + + /// + /// Get the last changed date of a specific addressbook. + /// + /// The Guid of AddreessBook. + /// + internal string GetAddressBookLastChange(Guid abId) + { + return GetAddressBookLastChange(abId.ToString("D")); + + } + + /// + /// Get the last changed date of a specific addressbook. + /// + /// The Guid of AddreessBook. + /// + internal string GetAddressBookLastChange(string abId) + { + string lowerId = abId.ToLowerInvariant(); + + if (HasAddressBook(lowerId)) + { + lock (AddressBooksInfo) + return AddressBooksInfo[lowerId].lastChange; + } + + return WebServiceConstants.ZeroTime; + } + + /// + /// Set information for a specific addressbook. + /// + /// AddressBook guid. + /// The addressbook info. + internal void SetAddressBookInfo(Guid abId, ABFindContactsPagedResultTypeAB abHeader) + { + SetAddressBookInfo(abId.ToString("D"), abHeader); + } + + /// + /// Set information for a specific addressbook. + /// + /// AddressBook guid. + /// The addressbook info. + internal void SetAddressBookInfo(string abId, ABFindContactsPagedResultTypeAB abHeader) + { + lock(SyncObject) + { + string lowerId = abId.ToLowerInvariant(); + + string compareTime = GetAddressBookLastChange(lowerId); + + try + { + + DateTime oldTime = WebServiceDateTimeConverter.ConvertToDateTime(compareTime); + DateTime newTime = WebServiceDateTimeConverter.ConvertToDateTime(abHeader.lastChange); + if (oldTime >= newTime) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Update addressbook information skipped, abId: " + + abId + ", LastChange: " + abHeader.lastChange + ", compared with: " + compareTime); + return; //Not necessary to update. + } + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "An error occured while setting AddressBook LastChange property, abId: " + + abId + ", LastChange: " + abHeader.lastChange + "\r\nError message: " + ex.Message); + return; + } + + SetAddressBookInfoToABInfoList(lowerId, abHeader); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Update addressbook information succeed, abId: " + + abId + ", LastChange: " + abHeader.lastChange + ", compared with: " + compareTime); + } + } + + + public SerializableDictionary MyProperties + { + get + { + return myproperties; + } + set + { + myproperties = value; + } + } + + public SerializableDictionary Groups + { + get + { + return groups; + } + + set + { + groups = value; + } + } + + /// + /// The contact list for different address book pages.

+ /// The circle recreate procedure is based on this property. + ///
+ public SerializableDictionary> AddressbookContacts + { + get + { + return abcontacts; + } + set + { + abcontacts = value; + } + } + + public void AddGroup(Dictionary range) + { + lock(SyncObject) + { + foreach (GroupType group in range.Values) + { + AddGroup(group); + } + } + } + + public void AddGroup(GroupType group) + { + lock(SyncObject) + { + Guid key = new Guid(group.groupId); + if (groups.ContainsKey(key)) + { + groups[key] = group; + } + else + { + groups.Add(key, group); + } + } + } + + public virtual void Add(string abId, Dictionary range) + { + lock(SyncObject) + { + string lowerId = abId.ToLowerInvariant(); + + if (!abcontacts.ContainsKey(lowerId)) + { + abcontacts.Add(lowerId, new SerializableDictionary(0)); + } + + foreach (Guid guid in range.Keys) + { + abcontacts[lowerId][guid] = range[guid]; + } + } + } + + public XMLContactList Merge(ABFindContactsPagedResultType forwardList) + { + lock(SyncObject) + { + Initialize(); + + #region AddressBook changed + + DateTime dt1 = WebServiceDateTimeConverter.ConvertToDateTime(GetAddressBookLastChange(forwardList.Ab.abId)); + DateTime dt2 = WebServiceDateTimeConverter.ConvertToDateTime(forwardList.Ab.lastChange); + + MergeIndividualAddressBook(forwardList); + MergeGroupAddressBook(forwardList); + #endregion + + //NO DynamicItems any more + + return this; + } + } + + /// + /// Update members for circles. + /// + /// + internal void MergeGroupAddressBook(ABFindContactsPagedResultType forwardList) + { + lock(SyncObject) + { + #region Get Individual AddressBook Information (Circle information) + + if (forwardList.Ab != null && forwardList.Ab.abId != WebServiceConstants.MessengerIndividualAddressBookId && + forwardList.Ab.abInfo.AddressBookType == AddressBookType.Group && + WebServiceDateTimeConverter.ConvertToDateTime(GetAddressBookLastChange(forwardList.Ab.abId)) < + WebServiceDateTimeConverter.ConvertToDateTime(forwardList.Ab.lastChange)) + { + SetAddressBookInfo(forwardList.Ab.abId, forwardList.Ab); + SaveAddressBookContactPage(forwardList.Ab.abId, forwardList.Contacts); + + //Create or update circle. + Circle targetCircle = UpdateCircleFromAddressBook(forwardList.Ab.abId); + + if (targetCircle != null) + { + //Update circle mebers. + UpdateCircleMembersFromAddressBookContactPage(targetCircle, Scenario.Initial); + switch (targetCircle.CircleRole) + { + case CirclePersonalMembershipRole.Admin: + case CirclePersonalMembershipRole.AssistantAdmin: + case CirclePersonalMembershipRole.Member: + AddCircleToCircleList(targetCircle); + break; + + case CirclePersonalMembershipRole.StatePendingOutbound: + FireJoinCircleInvitationReceivedEvents(targetCircle); + + break; + } + + if (IsPendingCreateConfirmCircle(targetCircle.AddressBookId)) + { + FireCreateCircleCompletedEvent(targetCircle); + } + + #region Print Info + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Getting non-default addressbook: \r\nId: " + + forwardList.Ab.abId + "\r\nName: " + forwardList.Ab.abInfo.name + + "\r\nType: " + forwardList.Ab.abInfo.AddressBookType + "\r\nMembers:"); + + string id = forwardList.Ab.abId + "@" + CircleString.DefaultHostDomain; + foreach (ContactType contact in forwardList.Contacts) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "PassportName: " + contact.contactInfo.passportName + ", DisplayName: " + contact.contactInfo.displayName + ", Type: " + contact.contactInfo.contactType); + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "\r\n"); + + #endregion + + SaveContactTable(forwardList.Contacts); + + if (requestCircleCount > 0) + { + //Only the individual addressbook merge which contains new circles will cause this action. + requestCircleCount--; + if (requestCircleCount == 0) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "************This is the initial circle ADL, should be sent after the initial contact ADL **********" + ); + + Save(); + NSMessageHandler.ContactService.SendInitialADL(Scenario.SendInitialCirclesADL); + } + } + } + else + { + RemoveCircleInverseInfo(forwardList.Ab.abId); + RemoveAddressBookContatPage(forwardList.Ab.abId); + RemoveAddressBookInfo(forwardList.Ab.abId); + + //Error? Save! + Save(); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "An error occured while merging the GroupAddressBook, addressbook info removed: " + + forwardList.Ab.abId); + } + } + + #endregion + } + } + + /// + /// + /// + /// + /// + /// This function must be called after the ContactTable and WLConnections are created. + private bool FireJoinCircleInvitationReceivedEvents(Circle circle) + { + lock (PendingAcceptionCircleList) + { + PendingAcceptionCircleList.AddCircle(circle); + } + + CircleEventArgs joinArgs = new CircleEventArgs(circle); + NSMessageHandler.ContactService.OnJoinCircleInvitationReceived(joinArgs); + return true; + } + + private bool FireCreateCircleCompletedEvent(Circle newCircle) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Newly created circle detected, create circle operation succeeded: " + newCircle); + RemoveABIdFromPendingCreateCircleList(newCircle.AddressBookId); + NSMessageHandler.ContactService.OnCreateCircleCompleted(new CircleEventArgs(newCircle)); + return true; + } + + private ContactType SelectMeContactFromAddressBookContactPage(string abId) + { + if (!HasAddressBookContactPage(abId)) + return null; + lock (AddressbookContacts) + return SelectMeContactFromContactList((new List(AddressbookContacts[abId.ToLowerInvariant()].Values)).ToArray()); + } + + /// + /// Get the addressbook's owner contact. + /// + /// + /// + private ContactType SelectMeContactFromContactList(ContactType[] contactList) + { + if (contactList == null) + return null; + + foreach (ContactType contact in contactList) + { + if (contact.contactInfo != null) + { + if (contact.contactInfo.contactType == MessengerContactType.Me) + return contact; + } + } + + return null; + } + + internal Guid SelectSelfContactGuid(string abId) + { + ContactType self = SelectSelfContactFromAddressBookContactPage(abId); + if (self == null) + return Guid.Empty; + + return new Guid(self.contactId); + } + + private ContactType SelectSelfContactFromAddressBookContactPage(string abId) + { + if (!HasAddressBookContactPage(abId)) + return null; + + if (NSMessageHandler.ContactList.Owner == null) + return null; + + lock (AddressbookContacts) + return SelectSelfContactFromContactList((new List(AddressbookContacts[abId.ToLowerInvariant()].Values)).ToArray(), NSMessageHandler.ContactList.Owner.Mail); + } + + /// + /// Get the owner of default addressbook in a certain addressbook page. This contact will used for exiting circle. + /// + /// + /// + /// + private ContactType SelectSelfContactFromContactList(ContactType[] contactList, string currentUserAccount) + { + if (contactList == null) + return null; + + string lowerAccount = currentUserAccount.ToLowerInvariant(); + + foreach (ContactType contact in contactList) + { + if (contact.contactInfo != null) + { + if (contact.contactInfo.passportName.ToLowerInvariant() == lowerAccount) + return contact; + } + } + + return null; + } + + /// + /// Update the circle members and other information from a newly receive addressbook. + /// This function can only be called after the contact page and WL connections were saved. + /// + /// + /// + private Circle UpdateCircleFromAddressBook(string abId) + { + if (abId != WebServiceConstants.MessengerIndividualAddressBookId) + { + string lowerId = abId.ToLowerInvariant(); + + + ContactType meContact = SelectMeContactFromAddressBookContactPage(lowerId); + CircleInverseInfoType inverseInfo = SelectCircleInverseInfo(lowerId); + + if (meContact == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "[UpdateCircleFromAddressBook] Cannot create circle since Me not found in addressbook. ABId: " + + abId); + return null; + } + + if (inverseInfo == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "[UpdateCircleFromAddressBook] Cannot create circle since inverse info not found in circle result list. ABId: " + + abId); + return null; + } + + Circle circle = NSMessageHandler.CircleList[new Guid(abId), inverseInfo.Content.Info.HostedDomain]; + + if (circle == null) + circle = CreateCircle(meContact, inverseInfo); + + return circle; + } + + return null; + } + + private bool UpdateCircleMembersFromAddressBookContactPage(Circle circle, Scenario scene) + { + string lowerId = circle.AddressBookId.ToString("D").ToLowerInvariant(); + if (!HasAddressBookContactPage(lowerId)) + return false; + + Dictionary newContactList = null; + Dictionary oldContactInverseList = null; + Contact[] oldContactList = null; + + bool isRestore = ((scene & Scenario.Restore) != Scenario.None); + + if (!isRestore) + { + newContactList = new Dictionary(); + oldContactInverseList = new Dictionary(); + oldContactList = circle.ContactList.ToArray(); + foreach (Contact contact in oldContactList) + { + oldContactInverseList[contact.CID] = contact; + } + } + + lock (AddressbookContacts) + { + SerializableDictionary page = AddressbookContacts[lowerId]; + + foreach (ContactType contactType in page.Values) + { + if (!isRestore) + newContactList[contactType.contactInfo.CID] = contactType; + + Contact tmpContact; + if ((UpdateContact(contactType, lowerId, circle, out tmpContact) & ReturnState.ProcessNextContact) == ReturnState.None) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "[UpdateCircleMembersFromAddressBookContactPage] Create circle member failed: " + + contactType.contactInfo.passportName + ", UpdateContact returns false."); + } + } + } + + if (isRestore) + return true; + + foreach (ContactType contactType in newContactList.Values) + { + if (contactType.contactInfo == null) + continue; + + string passportName = contactType.contactInfo.passportName; + + if (String.IsNullOrEmpty(passportName) && contactType.contactInfo.emails != null) + { + foreach (contactEmailType emailType in contactType.contactInfo.emails) + { + if (emailType.contactEmailType1 == ContactEmailTypeType.ContactEmailMessenger && + !String.IsNullOrEmpty(emailType.email)) + { + passportName = emailType.email; + break; + } + } + } + + if (!oldContactInverseList.ContainsKey(contactType.contactInfo.CID) && + circle.ContactList.HasContact(passportName, ClientType.PassportMember)) + { + circle.NSMessageHandler.ContactService.OnCircleMemberJoined(new CircleMemberEventArgs(circle, circle.ContactList[passportName, ClientType.PassportMember])); + } + } + + foreach (Contact contact in oldContactList) + { + if (!newContactList.ContainsKey(contact.CID)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Member " + contact.ToString() + " has left circle " + circle.ToString()); + circle.ContactList.Remove(contact.Mail, contact.ClientType); + circle.NSMessageHandler.ContactService.OnCircleMemberLeft(new CircleMemberEventArgs(circle, contact)); + } + } + + return true; + } + + internal void MergeIndividualAddressBook(ABFindContactsPagedResultType forwardList) + { + lock(SyncObject) + { + #region Get Default AddressBook Information + + if (forwardList.Ab != null && + WebServiceDateTimeConverter.ConvertToDateTime(GetAddressBookLastChange(forwardList.Ab.abId)) < + WebServiceDateTimeConverter.ConvertToDateTime(forwardList.Ab.lastChange) + && forwardList.Ab.abId == WebServiceConstants.MessengerIndividualAddressBookId) + { + Scenario scene = Scenario.None; + + if (IsContactTableEmpty()) + scene = Scenario.Initial; + else + scene = Scenario.DeltaRequest; + + #region Get groups + + if (null != forwardList.Groups) + { + foreach (GroupType groupType in forwardList.Groups) + { + Guid key = new Guid(groupType.groupId); + if (groupType.fDeleted) + { + Groups.Remove(key); + + ContactGroup contactGroup = NSMessageHandler.ContactGroups[groupType.groupId]; + if (contactGroup != null) + { + NSMessageHandler.ContactGroups.RemoveGroup(contactGroup); + NSMessageHandler.ContactService.OnContactGroupRemoved(new ContactGroupEventArgs(contactGroup)); + } + } + else + { + Groups[key] = groupType; + + // Add a new group + NSMessageHandler.ContactGroups.AddGroup( + new ContactGroup(System.Web.HttpUtility.UrlDecode(groupType.groupInfo.name), groupType.groupId, NSMessageHandler, groupType.groupInfo.IsFavorite)); + + // Fire the event + NSMessageHandler.ContactService.OnContactGroupAdded( + new ContactGroupEventArgs(NSMessageHandler.ContactGroups[groupType.groupId])); + } + } + } + + #endregion + + #region Process Contacts + + SortedDictionary newCIDList = new SortedDictionary(); + Dictionary newInverseInfos = new Dictionary(); + + Dictionary modifiedConnections = new Dictionary(); + + if (forwardList.CircleResult != null && forwardList.CircleResult.Circles != null) + { + foreach (CircleInverseInfoType info in forwardList.CircleResult.Circles) + { + string abId = info.Content.Handle.Id.ToLowerInvariant(); + + if (HasWLConnection(abId)) + { + if (!modifiedConnections.ContainsKey(abId)) + { + modifiedConnections[abId] = info; + } + } + else + { + newInverseInfos[abId] = info; + } + } + } + + if (null != forwardList.Contacts) + { + foreach (ContactType contactType in forwardList.Contacts) + { + if (null != contactType.contactInfo) + { + SetContactToAddressBookContactPage(forwardList.Ab.abId, contactType); + + /* + * Circle update rules: + * 1. If your own circle has any update (i.e. adding or deleting members), no hidden representative will be changed, only circle inverse info will be provided. + * 2. If a remote owner removes you from his circle, the hidden representative of that circle will change its RelationshipState to 2, circle inverse info will not provided. + * 3. If a remote owner re-adds you into a circle which you've left before, the hidden representative will be created, its relationshipState is 3, and the circle inverse info will be provided. + * 4. If you are already in a circle, the circle's owner removed you, then add you back, the hidden representative's RelationshipState property in NetworkInfo will change from 2 to 3. + * 5. If a remote contact has left your own circle, hidden representative will not change but circle inverse info will be provided. + * 6. If you delete your own circle, the hidden representative's contactType will change, and circle reverse info will be provided. + * 7. If you create a circle, the hidden representative will also create and circle inverse info will be provided. + * 8. If a remote owner invites you to join a circle, the hidden representative will be created, its relationshipState is 1 and circle inverse info will be provided, Role = StatePendingOutbound. + */ + long CID = contactType.contactInfo.CID; + + if (HasContact(CID)) + { + //modifiedConnections[CID] = SelectCircleInverseInfo(SelectWLConnection(CID)); + + ContactType savedContact = SelecteContact(contactType.contactInfo.CID); + //A deleted or modified circle; We are NOT in initial scene. + + if (savedContact.contactInfo.contactType == MessengerContactType.Circle) + { + if (savedContact.contactInfo.contactType != contactType.contactInfo.contactType) + { + //Owner deleted circles found. + //The members in the circle which this contact represents are all livepending contacts. + //Or, the circle this contact represents has no member. + //ModifyCircles(contactType, forwardList.CircleResult); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "A deleted circle found: contactType: " + contactType.contactInfo.contactType + "\r\n " + + "CID: " + contactType.contactInfo.CID.ToString() + "\r\n " + + "PassportName: " + contactType.contactInfo.passportName + "\r\n " + + "DomainTag: " + GetHiddenRepresentativeDomainTag(contactType) + "\r\n " + + "RelationshipState: " + GetCircleMemberRelationshipStateFromNetworkInfo(contactType.contactInfo.NetworkInfoList).ToString() + + "\r\n"); + } + else + { + //We may remove by the circle owner, so a circle is deleted. + //ModifyCircles(contactType, forwardList.CircleResult); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "A modified circle found: contactType: " + contactType.contactInfo.contactType + "\r\n " + + "CID: " + contactType.contactInfo.CID.ToString() + "\r\n " + + "PassportName: " + contactType.contactInfo.passportName + "\r\n " + + "DomainTag: " + GetHiddenRepresentativeDomainTag(contactType) + "\r\n " + + "RelationshipState: " + GetCircleMemberRelationshipStateFromNetworkInfo(contactType.contactInfo.NetworkInfoList).ToString() + + "\r\n"); + } + + continue; + } + } + else + { + + if (contactType.contactInfo.contactType == MessengerContactType.Circle) + { + RelationshipState state = GetCircleMemberRelationshipStateFromNetworkInfo(contactType.contactInfo.NetworkInfoList); + + //switch (state) + //{ + // case RelationshipState.Accepted: + // case RelationshipState.WaitingResponse: + // newCIDList[CID] = CID; + // break; + //} + + //We get the hidden representative of a new circle. + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "A circle contact found: contactType: " + contactType.contactInfo.contactType + "\r\n " + + "CID: " + contactType.contactInfo.CID.ToString() + "\r\n " + + "PassportName: " + contactType.contactInfo.passportName + "\r\n " + + "DomainTag: " + GetHiddenRepresentativeDomainTag(contactType) + "\r\n " + + "RelationshipState: " + GetCircleMemberRelationshipStateFromNetworkInfo(contactType.contactInfo.NetworkInfoList).ToString() + + "\r\n"); + continue; + } + } + + Contact contact = NSMessageHandler.ContactList.GetContactByGuid(new Guid(contactType.contactId)); + + if (contactType.fDeleted) + { + //The contact was deleted. + + RemoveContactFromAddressBook(forwardList.Ab.abId, new Guid(contactType.contactId)); + + if (contact != null) + { + contact.RemoveFromList(MSNLists.ForwardList); + NSMessageHandler.ContactService.OnContactRemoved(new ListMutateEventArgs(contact, MSNLists.ForwardList)); + + contact.Guid = Guid.Empty; + contact.SetIsMessengerUser(false); + + PresenceStatus oldStatus = contact.Status; + contact.SetStatus(PresenceStatus.Offline); //Force the contact offline. + NSMessageHandler.OnContactStatusChanged(new ContactStatusChangedEventArgs(contact, oldStatus)); + NSMessageHandler.OnContactOffline(new ContactEventArgs(contact)); + + + if (MSNLists.None == contact.Lists) + { + NSMessageHandler.ContactList.Remove(contact.Mail, contact.ClientType); + contact.NSMessageHandler = null; + } + } + } + else + { + if (UpdateContact(contactType, out contact) != ReturnState.UpdateError && + contact != null) + { + NSMessageHandler.ContactService.OnContactAdded(new ListMutateEventArgs(contact, MSNLists.ForwardList)); + } + } + } + } + } + + if (forwardList.Ab != null) + { + // Update lastchange + SetAddressBookInfo(forwardList.Ab.abId, forwardList.Ab); + } + + SaveContactTable(forwardList.Contacts); + if (forwardList.CircleResult != null) + SaveCircleInverseInfo(forwardList.CircleResult.Circles); + + + ProcessCircles(modifiedConnections, newInverseInfos, scene); + } + + #endregion + + #endregion + } + } + + private void ProcessCircles(Dictionary modifiedConnections, Dictionary newInverseInfos, Scenario scene) + { + int[] result = new int[] { 0, 0 }; + //We must process modified circles first. + result = ProcessModifiedCircles(modifiedConnections, scene | Scenario.ModifiedCircles); + result = ProcessNewConnections(newInverseInfos, scene | Scenario.NewCircles); + } + + private int[] ProcessNewConnections(Dictionary newInverseInfos, Scenario scene) + { + int added = 0; + int pending = 0; + + SaveWLConnection(newInverseInfos); + List abIds = new List(newInverseInfos.Keys); + + string[] filteredAbIds = SelectWLConnection(abIds, RelationshipState.Accepted); + RequestCircles(filteredAbIds, RelationshipState.Accepted, scene); + added = filteredAbIds.Length; + + filteredAbIds = SelectWLConnection(abIds, RelationshipState.WaitingResponse); + RequestCircles(filteredAbIds, RelationshipState.WaitingResponse, scene); + pending = filteredAbIds.Length; + + return new int[] { added, pending }; + } + + private int[] ProcessModifiedCircles(Dictionary modifiedConnections, Scenario scene) + { + int deleted = 0; + int reAdded = 0; + + Dictionary connectionClone = new Dictionary(modifiedConnections); + foreach (string abId in modifiedConnections.Keys) + { + CircleInverseInfoType inverseInfo = SelectWLConnection(abId); + if (inverseInfo != null && modifiedConnections[abId].Deleted) + { + RemoveCircle(modifiedConnections[abId].Content.Handle.Id); + connectionClone.Remove(abId); + deleted++; + } + } + + SaveWLConnection(connectionClone); + + string[] slectedABIds = SelectWLConnection(new List(connectionClone.Keys), RelationshipState.Accepted); //Select the re-added circles. + RequestCircles(slectedABIds, RelationshipState.Accepted, scene); + reAdded = slectedABIds.Length; + + return new int[] { deleted, reAdded }; + } + + private bool SaveWLConnection(Dictionary inverseList) + { + if (inverseList == null) + return false; + + lock (CircleResults) + { + foreach (string abId in inverseList.Keys) + { + CircleResults[abId] = inverseList[abId]; + } + } + + return true; + } + + private bool SaveAddressBookContactPage(string abId, ContactType[] contacts) + { + if (contacts == null) + return false; + + lock (AddressbookContacts) + { + SerializableDictionary page = new SerializableDictionary(0); + AddressbookContacts[abId.ToLowerInvariant()] = page; + foreach (ContactType contact in contacts) + { + page[new Guid(contact.contactId)] = contact; + } + } + + return true; + } + + private void SaveCircleInverseInfo(CircleInverseInfoType[] inverseInfoList) + { + List modifiedCircles = new List(0); + if (inverseInfoList != null) + { + foreach (CircleInverseInfoType circle in inverseInfoList) + { + string lowerId = circle.Content.Handle.Id.ToLowerInvariant(); + + lock (CircleResults) + { + + CircleResults[lowerId] = circle; + } + } + } + + } + + private void SaveContactTable(ContactType[] contacts) + { + if (contacts == null) + return; + + lock (contactTable) + { + foreach (ContactType contact in contacts) + { + if (contact.contactInfo != null) + { + contactTable[contact.contactInfo.CID] = contact; + } + } + } + } + + /// + /// Clean up the saved circle addressbook information. + /// + internal void ClearCircleInfos() + { + lock(SyncObject) + { + //lock (CircleResults) + CircleResults.Clear(); + + //lock (AddressBooksInfo) + AddressBooksInfo.Clear(); + + //lock (AddressbookContacts) + AddressbookContacts.Clear(); + + //lock (contactTable) + contactTable.Clear(); + + } + + } + + /// + /// 1. RemoveAddressBookContatPage + /// 2. RemoveAddressBookInfo + /// 3. RemoveCircleInverseInfo + /// 4. BreakWLConnection + /// 5. RemoveCircle + /// + /// + /// + internal bool RemoveCircle(string abId) + { + lock(SyncObject) + { + if (!string.IsNullOrEmpty(abId)) + { + CircleInverseInfoType inversoeInfo = SelectCircleInverseInfo(abId); + Circle tempCircle = null; + if (inversoeInfo != null) + { + tempCircle = NSMessageHandler.CircleList[new Guid(abId), inversoeInfo.Content.Info.HostedDomain]; + } + + //1. Remove corresponding addressbook page. + RemoveAddressBookContatPage(abId); + + //2. Remove addressbook info. + RemoveAddressBookInfo(abId); + + //3. Remove circle inverse info. + RemoveCircleInverseInfo(abId); + + //4. Break the connection between hidden representative and addressbook. + BreakWLConnection(abId); + + //5. Remove the presentation data structure for a circle. + NSMessageHandler.CircleList.RemoveCircle(new Guid(abId), CircleString.DefaultHostDomain); + + if (tempCircle != null) + { + NSMessageHandler.ContactService.OnExitCircleCompleted(new CircleEventArgs(tempCircle)); + } + + return true; + } + + return false; + } + } + + internal bool RemoveCircleInverseInfo(string abId) + { + lock (SyncObject) + return CircleResults.Remove(abId.ToLowerInvariant()); + } + + /// + /// Break the CID-AbID relationship of hidden representative to addressbook. + /// + /// + /// + private bool BreakWLConnection(string abId) + { + if (!HasWLConnection(abId)) + return false; + + if (!HasWLConnection(abId)) + return false; + + lock (CircleResults) + { + return CircleResults.Remove(abId); + } + } + + private bool RemoveABIdFromPendingCreateCircleList(Guid abId) + { + lock (PendingCreateCircleList) + return PendingCreateCircleList.Remove(abId); + } + + + /// + /// Get a circle addressbook by addressbook identifier. + /// + /// + /// + /// + /// + private bool RequestAddressBookByABId(string abId, RelationshipState state, Scenario scene) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Requesting AddressBook by ABId: " + abId + ", Scenario: " + scene.ToString()); + + abId = abId.ToLowerInvariant(); + + abHandleType individualAB = new abHandleType(); + individualAB.ABId = abId; + individualAB.Cid = 0; + individualAB.Puid = 0; + + switch (state) + { + case RelationshipState.Accepted: + requestCircleCount++; + try + { + NSMessageHandler.ContactService.abRequest(PartnerScenario.Initial, individualAB, null); + } + catch (Exception ex1) + { + requestCircleCount--; + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[RequestAddressBookByABId] Error: " + ex1.Message); + } + break; + case RelationshipState.WaitingResponse: + try + { + NSMessageHandler.ContactService.abRequest(PartnerScenario.Initial, individualAB, null); + } + catch (Exception ex2) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[RequestAddressBookByABId] Error: " + ex2.Message); + } + break; + } + + return true; + } + + + /// + /// Create a circle. + /// + /// + /// + /// + private Circle CreateCircle(ContactType me, CircleInverseInfoType inverseInfo) + { + return new Circle(me, inverseInfo, NSMessageHandler); + } + + private bool AddCircleToCircleList(Circle circle) + { + bool result = NSMessageHandler.CircleList.AddCircle(circle); + + lock (PendingAcceptionCircleList) + { + if (PendingAcceptionCircleList[circle.AddressBookId, circle.HostDomain] != null) + { + NSMessageHandler.ContactService.OnJoinedCircleCompleted(new CircleEventArgs(NSMessageHandler.CircleList[circle.AddressBookId, circle.HostDomain])); + } + + PendingAcceptionCircleList.RemoveCircle(circle.AddressBookId, circle.HostDomain); + } + + return result; + } + + + private bool RestoreCircles(string[] abIds, RelationshipState state) + { + if (abIds == null) + return false; + + foreach (string abId in abIds) + { + RestoreCircleFromAddressBook(abId, state); + } + + return true; + } + + private bool RestoreCircleFromAddressBook(string abId, RelationshipState state) + { + string lowerId = abId.ToLowerInvariant(); + + if (lowerId == WebServiceConstants.MessengerIndividualAddressBookId) + return true; + + if (!HasAddressBook(lowerId)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "[RestoreCircleFromAddressBook] failed, cannot find specific addressbook :" + lowerId); + return false; + } + + if (!AddressbookContacts.ContainsKey(lowerId)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "[RestoreCircleFromAddressBook] failed, cannot find specific addressbook contact group:" + lowerId); + return false; + } + + //We use addressbook list to boot the restore procedure. + ContactType me = SelectMeContactFromContactList(new List(AddressbookContacts[lowerId].Values).ToArray()); + CircleInverseInfoType inverseInfo = SelectCircleInverseInfo(lowerId); + + if (me == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "[RestoreCircleFromAddressBook] Me Contact not found, restore circle failed:" + lowerId); + return false; + } + + if (inverseInfo == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "[RestoreCircleFromAddressBook] Circle inverse info not found, restore circle failed:" + lowerId); + return false; + } + + if (NSMessageHandler.CircleList[new Guid(lowerId), CircleString.DefaultHostDomain] != null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "[RestoreCircleFromAddressBook] circle already exists, restore skipped:" + lowerId); + return false; + } + + Circle circle = CreateCircle(me, inverseInfo); + UpdateCircleMembersFromAddressBookContactPage(circle, Scenario.Restore); + + switch (circle.CircleRole) + { + case CirclePersonalMembershipRole.Admin: + case CirclePersonalMembershipRole.AssistantAdmin: + case CirclePersonalMembershipRole.Member: + AddCircleToCircleList(circle); + break; + case CirclePersonalMembershipRole.StatePendingOutbound: + FireJoinCircleInvitationReceivedEvents(circle); + break; + } + + return true; + + } + + + private CircleInviter GetCircleInviterFromNetworkInfo(ContactType contact) + { + CircleInviter initator = null; + + if (contact.contactInfo.NetworkInfoList.Length > 0) + { + foreach (NetworkInfoType networkInfo in contact.contactInfo.NetworkInfoList) + { + if (networkInfo.DomainId == 1) + { + if (networkInfo.InviterCIDSpecified) + { + ContactType inviter = SelecteContact(networkInfo.InviterCID); + if (inviter == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[GetCircleInviterFromNetworkInfo] Cannot create circle inviter from CID: " + networkInfo.InviterCID + ", contact not found."); + return null; + } + + initator = new CircleInviter(inviter, networkInfo.InviterMessage); + } + else + { + initator = new CircleInviter(networkInfo.InviterEmail, networkInfo.InviterName, networkInfo.InviterMessage); + } + } + } + } + + return initator; + } + + /// + /// Use msn webservices to get addressbooks. + /// + /// + /// + /// + private void RequestCircles(string[] abIds, RelationshipState state, Scenario scene) + { + if (abIds == null) + return; + + foreach (string abId in abIds) + { + RequestAddressBookByABId(abId, state, scene); + } + + } + + private ReturnState UpdateContact(ContactType contactType, out Contact updatedContact) + { + return UpdateContact(contactType, WebServiceConstants.MessengerIndividualAddressBookId, null, out updatedContact); + } + + private ReturnState UpdateContact(ContactType contactType, string abId, Circle circle, out Contact updatedContact) + { + if (contactType.contactInfo == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "Cannot update contact, contact info is null."); + updatedContact = null; + return ReturnState.UpdateError; + } + + contactInfoType cinfo = contactType.contactInfo; + ClientType type = ClientType.PassportMember; + string account = cinfo.passportName; + string displayName = cinfo.displayName; + string nickName = GetContactNickName(contactType); + Uri userTileURL = GetUserTileURLFromWindowsLiveNetworkInfo(contactType); + bool isMessengeruser = cinfo.isMessengerUser; + string lowerId = abId.ToLowerInvariant(); + ReturnState returnValue = ReturnState.ProcessNextContact; + ContactList contactList = null; + bool isDefaultAddressBook = (lowerId == null || lowerId == WebServiceConstants.MessengerIndividualAddressBookId); + + if (cinfo.emails != null && account == null && cinfo != null) + { + foreach (contactEmailType cet in cinfo.emails) + { + if (cet.isMessengerEnabled) + { + type = (ClientType)Enum.Parse(typeof(ClientType), cet.Capability); + account = cet.email; + isMessengeruser |= cet.isMessengerEnabled; + displayName = account; + break; + } + } + } + + if (cinfo.phones != null && account == null) + { + foreach (contactPhoneType cpt in cinfo.phones) + { + if (cpt.isMessengerEnabled) + { + type = ClientType.PhoneMember; + account = cpt.number; + isMessengeruser |= cpt.isMessengerEnabled; + displayName = account; + break; + } + } + } + + if (account != null) + { + account = account.ToLowerInvariant(); + if (cinfo.contactType != MessengerContactType.Me) + { + #region Contacts other than owner + + Contact contact = null; + + if (isDefaultAddressBook) + { + contact = NSMessageHandler.ContactList.GetContact(account, type); + contactList = NSMessageHandler.ContactList; + } + else + { + if (circle == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "Cannot update contact: " + account + " in addressbook: " + abId); + + //This means we are restoring contacts from mcl file. + //We need to retore the circle first, then initialize this contact again. + updatedContact = null; + return ReturnState.UpdateError; + } + + CirclePersonalMembershipRole membershipRole = GetCircleMemberRoleFromNetworkInfo(cinfo.NetworkInfoList); + contact = circle.ContactList.GetContact(account, type); + contactList = circle.ContactList; + contact.CircleRole = membershipRole; + string tempName = GetCircleMemberDisplayNameFromNetworkInfo(cinfo.NetworkInfoList); + if (!string.IsNullOrEmpty(tempName)) + displayName = tempName; + } + + contact.Guid = new Guid(contactType.contactId); + contact.CID = Convert.ToInt64(cinfo.CID); + contact.ContactType = cinfo.contactType; + contact.SetHasSpace(cinfo.hasSpace); + contact.SetComment(cinfo.comment); + contact.SetIsMessengerUser(isMessengeruser); + contact.SetMobileAccess(cinfo.isMobileIMEnabled); + contact.UserTileURL = userTileURL; + SetContactPhones(contact, cinfo); + + if (!string.IsNullOrEmpty(nickName) && string.IsNullOrEmpty(contact.NickName)) + { + contact.SetNickName(nickName); + } + + + if (contact.IsMessengerUser) + { + contact.AddToList(MSNLists.ForwardList); //IsMessengerUser is only valid in AddressBook member + } + + if (!string.IsNullOrEmpty(displayName)) + { + if ((contact.Name == contact.Mail && displayName != contact.Mail) || + string.IsNullOrEmpty(contact.Name)) + { + contact.SetName(displayName); + } + } + + + if (cinfo.groupIds != null) + { + foreach (string groupId in cinfo.groupIds) + { + contact.ContactGroups.Add(NSMessageHandler.ContactGroups[groupId]); + } + } + + if (cinfo.groupIdsDeleted != null) + { + foreach (string groupId in cinfo.groupIdsDeleted) + { + contact.ContactGroups.Remove(NSMessageHandler.ContactGroups[groupId]); + } + } + + #endregion + + #region Filter yourself and members who alrealy left this circle. + bool needsDelete = false; + + RelationshipState relationshipState = GetCircleMemberRelationshipStateFromNetworkInfo(cinfo.NetworkInfoList); + if (((relationshipState & RelationshipState.Rejected) != RelationshipState.None || + relationshipState == RelationshipState.None) && + isDefaultAddressBook == false) + { + //Members who already left. + needsDelete |= true; + } + + if (cinfo.IsHiddenSpecified && cinfo.IsHidden) + { + needsDelete |= true; + } + + if (account == NSMessageHandler.ContactList.Owner.Mail.ToLowerInvariant() && + cinfo.NetworkInfoList != null && + type == NSMessageHandler.ContactList.Owner.ClientType && + isDefaultAddressBook == false) + { + //This is a self contact. If we need to left a circle, we need its contactId. + //The exit circle operation just delete this contact from addressbook. + needsDelete |= true; + } + + if (contactType.fDeleted) + { + needsDelete |= true; + } + + if (needsDelete && contact.Lists == MSNLists.None) + { + contactList.Remove(account, type); + } + + #endregion + + updatedContact = contact; + } + else + { + #region Update owner and Me contact + + Owner owner = null; + + if (lowerId == WebServiceConstants.MessengerIndividualAddressBookId) + { + owner = NSMessageHandler.ContactList.Owner; + if (owner == null) + { + owner = new Owner(abId, cinfo.passportName, Convert.ToInt64(cinfo.CID), NSMessageHandler); + NSMessageHandler.ContactList.SetOwner(owner); + } + } + else + { + if (circle == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "Cannot update owner: " + account + " in addressbook: " + abId); + updatedContact = null; + return ReturnState.UpdateError; + } + + owner = circle.ContactList.Owner; + } + + if (displayName == owner.Mail && !String.IsNullOrEmpty(owner.Name)) + { + displayName = owner.Name; + } + + owner.Guid = new Guid(contactType.contactId); + owner.CID = Convert.ToInt64(cinfo.CID); + owner.ContactType = cinfo.contactType; + + if (!string.IsNullOrEmpty(displayName) && string.IsNullOrEmpty(owner.Name)) + { + //We set display name by the addressbook information only if it's initially empty. + owner.SetName(displayName); + } + + if (!string.IsNullOrEmpty(nickName) && string.IsNullOrEmpty(owner.NickName)) + { + owner.SetNickName(nickName); + } + + owner.UserTileURL = userTileURL; + SetContactPhones(owner, cinfo); + #endregion + + if (null != cinfo.annotations && lowerId == WebServiceConstants.MessengerIndividualAddressBookId) + { + foreach (Annotation anno in cinfo.annotations) + { + MyProperties[anno.Name] = anno.Value; + } + } + + InitializeMyProperties(); + + updatedContact = owner; + } + } + else + { + updatedContact = null; + } + + return returnValue; + } + + private bool SetContactPhones(Contact contact, contactInfoType cinfo) + { + if (cinfo == null || cinfo.phones == null) + return false; + + foreach (contactPhoneType cp in cinfo.phones) + { + contact.PhoneNumbers[cp.contactPhoneType1] = cp.number; + } + + return true; + } + + /// + /// Get a contact's nick name from it's Annotations. + /// + /// + /// + private string GetContactNickName(ContactType contact) + { + if (contact.contactInfo == null) + return string.Empty; + + if (contact.contactInfo.annotations == null) + return string.Empty; + + foreach (Annotation anno in contact.contactInfo.annotations) + { + if (anno.Name == AnnotationNames.AB_NickName) + { + return anno.Value; + } + } + + return string.Empty; + } + + /// + /// Get windows live user title url. + /// + /// + /// + private Uri GetUserTileURLFromWindowsLiveNetworkInfo(ContactType contact) + { + string returnURL = GetUserTileURLByDomainIdFromNetworkInfo(contact, DomainIds.WLDomain); + try + { + Uri urlResult = null; + if (Uri.TryCreate(returnURL, UriKind.Absolute, out urlResult)) + return urlResult; + } + catch (Exception) + { + + } + + return null; + } + + /// + /// Get user title url. + /// + /// + /// + /// + private string GetUserTileURLByDomainIdFromNetworkInfo(ContactType contact, int domainId) + { + if (contact.contactInfo == null) + return string.Empty; + if (contact.contactInfo.NetworkInfoList == null) + return string.Empty; + + foreach (NetworkInfoType info in contact.contactInfo.NetworkInfoList) + { + if (info.DomainIdSpecified && info.DomainId == domainId) + { + if (!string.IsNullOrEmpty(info.UserTileURL)) + { + return info.UserTileURL; + } + } + } + + return string.Empty; + + } + + /// + /// Get a contact's RelationshipState property by providing DomainId = 1 and RelationshipType = 5. + /// + /// + /// + private RelationshipState GetCircleMemberRelationshipStateFromNetworkInfo(NetworkInfoType[] infoList) + { + return (RelationshipState)GetContactRelationshipStateFromNetworkInfo(infoList, DomainIds.WLDomain, RelationshipTypes.CircleGroup); + } + + /// + /// Get a contact's RelationshipState property by providing DomainId and RelationshipType + /// + /// + /// + /// + /// + private int GetContactRelationshipStateFromNetworkInfo(NetworkInfoType[] infoList, int domainId, int relationshipType) + { + if (infoList == null) + return 0; + + foreach (NetworkInfoType info in infoList) + { + if (info.RelationshipTypeSpecified && info.DomainIdSpecified && info.RelationshipStateSpecified) + { + if (info.DomainId == domainId && info.RelationshipType == relationshipType) + { + return info.RelationshipState; + } + } + } + + return 0; + } + + private string GetCircleMemberDisplayNameFromNetworkInfo(NetworkInfoType[] infoList) + { + return GetContactDisplayNameFromNetworkInfo(infoList, DomainIds.WLDomain, RelationshipTypes.CircleGroup); + } + + private string GetContactDisplayNameFromNetworkInfo(NetworkInfoType[] infoList, int domainId, int relationshipType) + { + if (infoList == null) + return string.Empty; + + foreach (NetworkInfoType info in infoList) + { + if (info.RelationshipTypeSpecified && info.DomainIdSpecified && !string.IsNullOrEmpty(info.DisplayName)) + { + if (info.DomainId == domainId && info.RelationshipType == relationshipType) + { + return info.DisplayName; + } + } + } + + return string.Empty; + } + + + private CirclePersonalMembershipRole GetCircleMemberRoleFromNetworkInfo(NetworkInfoType[] infoList) + { + return (CirclePersonalMembershipRole)GetContactRelationshipRoleFromNetworkInfo(infoList, DomainIds.WLDomain, RelationshipTypes.CircleGroup); + } + + private int GetContactRelationshipRoleFromNetworkInfo(NetworkInfoType[] infoList, int domainId, int relationshipType) + { + if (infoList == null) + return 0; + + foreach (NetworkInfoType info in infoList) + { + if (info.RelationshipTypeSpecified && info.DomainIdSpecified && info.RelationshipRoleSpecified) + { + if (info.DomainId == domainId && info.RelationshipType == relationshipType) + { + return info.RelationshipRole; + } + } + } + + return 0; + } + + /// + /// Get the domain tage of circle's hidden repersentative. + /// + /// + /// + private string GetHiddenRepresentativeDomainTag(ContactType contact) + { + if (contact.contactInfo == null) + return string.Empty; + + if (contact.contactInfo.contactType != MessengerContactType.Circle) + return string.Empty; + + return GetDomainTagFromNetworkInfo(contact.contactInfo.NetworkInfoList, DomainIds.WLDomain); + } + + private string GetDomainTagFromNetworkInfo(NetworkInfoType[] infoList, int domainId) + { + if (infoList == null) + return string.Empty; + + foreach (NetworkInfoType info in infoList) + { + if (info.DomainIdSpecified && !string.IsNullOrEmpty(info.DomainTag)) + { + if (info.DomainId == domainId) + return info.DomainTag; + } + } + + return string.Empty; + } + + private bool AddToContactTable(long CID, ContactType contact) + { + if (contact.contactInfo == null) + return false; + + lock (contactTable) + contactTable[CID] = contact; + return true; + } + + + /// + /// Set MyProperties to default value. + /// + public void InitializeMyProperties() + { + lock(SyncObject) + { + if (!MyProperties.ContainsKey(AnnotationNames.MSN_IM_MBEA)) + MyProperties[AnnotationNames.MSN_IM_MBEA] = "0"; + + if (!MyProperties.ContainsKey(AnnotationNames.MSN_IM_GTC)) + MyProperties[AnnotationNames.MSN_IM_GTC] = "1"; + + if (!MyProperties.ContainsKey(AnnotationNames.MSN_IM_BLP)) + MyProperties[AnnotationNames.MSN_IM_BLP] = "0"; + + if (!MyProperties.ContainsKey(AnnotationNames.MSN_IM_MPOP)) + MyProperties[AnnotationNames.MSN_IM_MPOP] = "1"; + + if (!MyProperties.ContainsKey(AnnotationNames.MSN_IM_RoamLiveProperties)) + MyProperties[AnnotationNames.MSN_IM_RoamLiveProperties] = "1"; + + if (!MyProperties.ContainsKey(AnnotationNames.Live_Profile_Expression_LastChanged)) + MyProperties[AnnotationNames.Live_Profile_Expression_LastChanged] = XmlConvert.ToString(DateTime.MinValue, "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzzzzz"); + } + } + + #endregion + + #region Overrides + + /// + /// Save the into a specified file. + /// + /// + public override void Save(string filename) + { + + lock(SyncObject) + { + try + { + Version = Properties.Resources.XMLContactListVersion; + base.Save(filename); + }catch(Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "An error occurs while saving the Addressbook, StackTrace:\r\n" + + ex.StackTrace); + } + } + } + #endregion + + } +}; diff --git a/MSNPSharp/MSNObject.cs b/MSNPSharp/MSNObject.cs new file mode 100644 index 0000000..b77352b --- /dev/null +++ b/MSNPSharp/MSNObject.cs @@ -0,0 +1,783 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Web; +using System.Xml; +using System.Text; +using System.Collections.Generic; +using System.Collections; +using System.Diagnostics; +using System.Globalization; +using System.Security.Cryptography; +using System.Text.RegularExpressions; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + /// + /// Defines the type of MSNObject. + /// Thanks for ZoroNaX : http://zoronax.spaces.live.com/blog/cns!4A0B813054895814!180.entry + /// + public enum MSNObjectType + { + /// + /// Unknown msnobject type. + /// + Unknown = 0, + /// + /// Avatar, Unknown + /// + Avatar = 1, + /// + /// Emotion icon. + /// + Emoticon = 2, + /// + /// User display image. + /// + UserDisplay = 3, + /// + /// ShareFile, Unknown + /// + ShareFile = 4, + /// + /// Background image. + /// + Background = 5, + /// + /// History + /// + History = 6, + /// + /// Deluxe Display Pictures + /// + DynamicPicture = 7, + /// + /// flash emoticon + /// + Wink = 8, + /// + /// Map File A map file contains a list of items in the store. + /// + MapFile = 9, + /// + /// Dynamic Backgrounds + /// + DynamicBackground = 10, + /// + /// Voice Clip + /// + VoiceClip = 11, + /// + /// Plug-In State. Saved state of Add-ins. + /// + SavedState = 12, + /// + /// Roaming Objects. For example, your roaming display picture. + /// + RoamingObject = 13, + /// + /// Signature sound + /// + SignatureSound = 14 + } + + /// + /// The MSNObject can hold an image, display, emoticon, etc. + /// + [Serializable()] + public class MSNObject + { + private string oldHash = string.Empty; + + [NonSerialized] + private PersistentStream dataStream = null; + + + private string fileLocation = string.Empty; + private string creator = string.Empty; + private int size = 0; + private MSNObjectType type = MSNObjectType.Unknown; + private string location = string.Empty; + private string sha = string.Empty; + + private object syncObject = new object(); + + public object SyncObject + { + get { return syncObject; } + } + + /// + /// The datastream to write to, or to read from + /// + protected PersistentStream DataStream + { + get + { + lock (SyncObject) + return dataStream; + } + set + { + lock (SyncObject) + { + if (dataStream != null) + dataStream.Close(); + + dataStream = value; + UpdateStream(); + } + } + } + + /// + /// Update the size and SHA info after the DataStream property has been changed. + /// + protected void UpdateStream() + { + if (DataStream != null) + { + Size = (int)DataStream.Length; + Sha = GetStreamHash(DataStream); + } + } + + /// + /// The local contact list owner + /// + public string Creator + { + get + { + return creator; + } + set + { + creator = value; + UpdateInCollection(); + } + } + + /// + /// The total data size + /// + public int Size + { + get + { + return size; + } + + private set + { + size = value; + UpdateInCollection(); + } + } + + /// + /// The type of MSN Object + /// + public MSNObjectType ObjectType + { + get + { + return type; + } + set + { + type = value; + UpdateInCollection(); + } + } + + /// + /// The location of the object. This is a location on the hard-drive. Use relative paths. This is only a text string; na data is read in after setting this field. Use FileLocation for that purpose. + /// + public string Location + { + get + { + return location; + } + set + { + location = value; + UpdateInCollection(); + } + } + + /// + /// [Deprecated, use LoadFile()] Gets or sets the file location. When a file is set the file data is immediately read in memory to extract the filehash. It will retain in memory afterwards. + /// + public string FileLocation + { + get + { + return fileLocation; + } + set + { + this.LoadFile(value); + fileLocation = value; + } + } + + /// + /// Gets or sets the file location. When a file is set the file data is immediately read in memory to extract the filehash. It will retain in memory afterwards. + /// + /// + public void LoadFile(string fileName) + { + FileInfo finfo = new FileInfo(fileName); + if (finfo.Exists) + { + if (this.fileLocation == fileName) + return; + this.fileLocation = fileName; + this.location = Path.GetRandomFileName(); + + // and open a new stream + PersistentStream persistentStream = new PersistentStream(new MemoryStream()); + + // copy the file + byte[] buffer = new byte[512]; + Stream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read); + int cnt = 0; + while ((cnt = fileStream.Read(buffer, 0, 512)) > 0) + { + persistentStream.Write(buffer, 0, cnt); + } + + DataStream = persistentStream; + + UpdateInCollection(); + } + } + + /// + /// The SHA1 encrypted hash of the datastream. + /// + /// + /// Usually the application programmer don't need to set this itself. + /// + public string Sha + { + get + { + return sha; + } + + set + { + sha = value; + UpdateInCollection(); + } + } + + /// + /// Updates the msn object in the global MSNObjectCatalog. + /// + public void UpdateInCollection() + { + if (oldHash.Length != 0) + MSNObjectCatalog.GetInstance().Remove(oldHash); + + oldHash = CalculateChecksum(); + + MSNObjectCatalog.GetInstance().Add(oldHash, this); + } + + /// + /// Calculates the hash of datastream. + /// + /// + /// + protected static string GetStreamHash(Stream stream) + { + stream.Seek(0, SeekOrigin.Begin); + + // fet file hash + byte[] bytes = new byte[(int)stream.Length]; + + //put bytes into byte array + stream.Read(bytes, 0, (int)stream.Length); + + //create SHA1 object + HashAlgorithm hash = new SHA1Managed(); + byte[] hashBytes = hash.ComputeHash(bytes); + + return Convert.ToBase64String(hashBytes); + } + + /// + /// Creates a MSNObject. + /// + public MSNObject() + { + DataStream = new PersistentStream(new MemoryStream()); + } + + /// + /// + /// + private static Regex contextRe = new Regex("(?[^= ]+)=\"(?[^\"]+)\""); + + /// + /// Parses a context send by the remote contact and set the corresponding class variables. Context input is assumed to be not base64 encoded. + /// + /// + public virtual void SetContext(string context) + { + SetContext(context, false); + } + + /// + /// Parses a context send by the remote contact and set the corresponding class variables. + /// + /// + /// + public virtual void SetContext(string context, bool base64Encoded) + { + + if (base64Encoded) + context = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(context)); + + string xmlString = context; + if (context.IndexOf(" ") == -1) + xmlString = GetDecodeString(context); + MatchCollection matches = contextRe.Matches(xmlString); + + foreach (Match match in matches) + { + string name = match.Groups["Name"].Value.ToLower(System.Globalization.CultureInfo.InvariantCulture); + string val = match.Groups["Value"].Value; + + switch (name) + { + case "creator": + this.creator = val; + break; + case "size": + this.size = int.Parse(val, System.Globalization.CultureInfo.InvariantCulture); + break; + case "type": + { + switch (val) + { + case "2": + type = MSNObjectType.Emoticon; + break; + case "3": + type = MSNObjectType.UserDisplay; + break; + case "5": + type = MSNObjectType.Background; + break; + case "8": + type = MSNObjectType.Wink; + break; + } + break; + } + case "location": + this.location = val; + break; + case "sha1d": + this.sha = val; + break; + } + } + } + + /// + /// Constructs a MSN object based on a (memory)stream. The client programmer is responsible for inserting this object in the global msn object collection. + /// The stream must remain open during the whole life-length of the application. + /// + /// + /// + /// + /// + public MSNObject(string creator, Stream inputStream, MSNObjectType type, string location) + { + this.creator = creator; + this.size = (int)inputStream.Length; + this.type = type; + this.location = location; + + this.sha = GetStreamHash(inputStream); + + this.DataStream = new PersistentStream(inputStream); + } + + /// + /// Constructs a MSN object based on a physical file. The client programmer is responsible for inserting this object in the global msn object collection. + /// + /// + /// + /// + public MSNObject(string creator, string fileLocation, MSNObjectType type) + { + this.location = Path.GetFullPath(fileLocation).Replace(Path.GetPathRoot(fileLocation), ""); + this.location += new Random().Next().ToString(CultureInfo.InvariantCulture); + + this.fileLocation = fileLocation; + + Stream stream = OpenStream(); + + this.creator = creator; + this.size = (int)stream.Length; + this.type = type; + + this.sha = GetStreamHash(stream); + stream.Close(); + } + + /// + /// Returns the stream to read from. In case of an in-memory stream that stream is returned. In case of a filelocation + /// a stream to the file will be opened and returned. The stream is not guaranteed to positioned at the beginning of the stream. + /// + /// + public virtual Stream OpenStream() + { + DataStream.Open(); + + // otherwise it's a memorystream + return DataStream; + } + + /// + /// Returns the "url-encoded xml" string for MSNObjects. + /// + /// + /// + public static string GetEncodeString(string context) + { + return MSNHttpUtility.MSNObjectUrlEncode(context); + } + + public static string GetDecodeString(string context) + { + if (context.IndexOf(" ") == -1) + { + return MSNHttpUtility.MSNObjectUrlDecode(context); + } + return context; + } + + + /// + /// Calculates the checksum for the entire MSN Object. + /// + /// This value is used to uniquely identify a MSNObject. + /// + public string CalculateChecksum() + { + string checksum = "Creator" + Creator + "Size" + Size + "Type" + (int)this.ObjectType + "Location" + Location + "FriendlyAAA=SHA1D" + Sha; + + HashAlgorithm shaAlg = new SHA1Managed(); + string baseEncChecksum = Convert.ToBase64String(shaAlg.ComputeHash(Encoding.UTF8.GetBytes(checksum))); + return baseEncChecksum; + } + + /// + /// The context as an url-encoded xml string. + /// + public string Context + { + get + { + return GetEncodedString(); + } + } + + /// + /// The context as an xml string, not url-encoded. + /// + public string ContextPlain + { + get + { + return GetXmlString(); + } + } + + /// + /// Returns the xml string. + /// + /// + protected virtual string GetXmlString() + { + return ""; + } + + /// + /// Returns the url-encoded xml string. + /// + /// + protected virtual string GetEncodedString() + { + return MSNHttpUtility.MSNObjectUrlEncode(GetXmlString()); + } + + + protected virtual bool ContextEqual(string contextPlain) + { + + if (Size == 0 && string.IsNullOrEmpty(contextPlain)) + return true; + + try + { + XmlDocument msnObjectDocument = new XmlDocument(); + msnObjectDocument.LoadXml(contextPlain); + XmlNode msnObjectNode = msnObjectDocument.SelectSingleNode("msnobj"); + string sha = msnObjectNode.Attributes["SHA1D"].InnerText; + string creator = msnObjectNode.Attributes["Creator"].InnerText; + MSNObjectType type = (MSNObjectType)int.Parse(msnObjectNode.Attributes["Type"].InnerText); + + return (Sha == sha && Creator == creator && type == ObjectType); + + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "MSNObject compare error: context " + + contextPlain + " is not a valid context for MSNObject.\r\n Error description: " + + ex.Message + "\r\n Stack Trace: " + ex.StackTrace); + return true; + } + + } + + + protected virtual bool MSNObjectEqual(MSNObject obj2) + { + if ((object)obj2 == null) + return false; + return GetHashCode() == obj2.GetHashCode(); + } + + + public static bool operator ==(MSNObject msnObject, object compareTarget) + { + if ((object)msnObject == null && compareTarget == null) + return true; + if ((object)msnObject == null || compareTarget == null) + return false; + return msnObject.Equals(compareTarget); + } + + public static bool operator !=(MSNObject msnObject, object compareTarget) + { + return !(msnObject == compareTarget); + } + + public override bool Equals(object obj) + { + if (object.ReferenceEquals(this, obj)) + return true; + + if (obj == null || obj is MSNObject) + return MSNObjectEqual(obj as MSNObject); + + if (obj is string) + return ContextEqual(GetDecodeString(obj.ToString())); + + return false; + } + + public override int GetHashCode() + { + return CalculateChecksum().GetHashCode(); + } + } + + + /// + /// A collection of all available MSN objects. This class is implemented following the singleton pattern. + /// + /// + /// In this collection all user display's, emoticons, etc for the entire application are stored. + /// This allows for easy retrieval of the corresponding msn object by passing in the encrypted hash. + /// Note: Use to get a reference to the global MSNObjectCatalog object on which you can call methods. + /// + [Serializable()] + public class MSNObjectCatalog : ICollection + { + /// + /// The single instance + /// + [NonSerialized] + private static MSNObjectCatalog instance = new MSNObjectCatalog(); + + /// + /// Collection of all msn objects + /// + private Dictionary objectCollection = new Dictionary(0); + + private object syncRoot = new object(); + + /// + /// Returns the msn object with the supplied hash as checksum. + /// + /// + /// + public MSNObject Get(string hash) + { + lock (SyncRoot) + return (objectCollection.ContainsKey(hash)) ? (MSNObject)objectCollection[hash] : null; + } + + /// + /// Removes the msn object with the specified checksum from the collection. + /// + /// + public void Remove(string checksum) + { + lock (SyncRoot) + objectCollection.Remove(checksum); + } + + /// + /// Removes the specified msn object from the collection. + /// + /// + public void Remove(MSNObject msnObject) + { + Remove(msnObject.CalculateChecksum()); + } + + /// + /// Adds the MSNObject (a user display, emoticon, etc) in the global collection. + /// + /// + public void Add(MSNObject msnObject) + { + string hash = msnObject.CalculateChecksum(); + Add(hash, msnObject); + } + + /// + /// Adds the MSNObject (a user display, emoticon, etc) in the global collection, with the specified checksum as index. + /// + /// + /// + public void Add(string checksum, MSNObject msnObject) + { + lock (SyncRoot) + objectCollection[checksum] = msnObject; + } + + /// + /// Returns a reference to the global MSNObjectCatalog object. + /// + public static MSNObjectCatalog GetInstance() + { + return instance; + } + + /// + /// Constructor. + /// + private MSNObjectCatalog() + { + } + + #region ICollection Members + + /// + /// Returns false,because ObjectCatalog is by default not synchronized. + /// + public bool IsSynchronized + { + get + { + return true; + } + } + + /// + /// The number of objects in the catalog. + /// + public int Count + { + get + { + lock (SyncRoot) + return objectCollection.Count; + } + } + + /// + /// + /// + /// + public void CopyTo(Array array, int index) + { + MSNObject[] msnObjectArray = array as MSNObject[]; + if (msnObjectArray != null) + { + lock (SyncRoot) + objectCollection.Values.CopyTo(msnObjectArray, index); + } + } + + /// + /// + public object SyncRoot + { + get + { + return syncRoot; + } + } + + #endregion + + #region IEnumerable Members + + /// + /// + /// + public IEnumerator GetEnumerator() + { + lock (SyncRoot) + return objectCollection.GetEnumerator(); + } + + #endregion + } +}; diff --git a/MSNPSharp/MSNPSharp.csproj b/MSNPSharp/MSNPSharp.csproj new file mode 100644 index 0000000..a360a04 --- /dev/null +++ b/MSNPSharp/MSNPSharp.csproj @@ -0,0 +1,496 @@ + + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {97CB2DC7-2FE8-4AF5-84D0-6B9872A5E960} + Library + Properties + MSNPSharp + MSNPSharp + true + Resources\msnpsharp.snk + v2.0 + + + 2.0 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + TRACE;DEBUG + prompt + 4 + bin\Debug\MSNPSharp.XML + 1591 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + + + + + + + + + + + + + Circle.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NSMessageHandler.cs + + + + + + + + + + + + + + P2PMessageSession.cs + + + + + + + True + True + Resources.resx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Reference.map + + + True + True + Reference.map + + + True + True + Reference.map + + + True + True + Reference.map + + + True + True + Reference.map + + + + + + + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Designer + + + Designer + + + + MSDiscoCodeGenerator + Reference.cs + + + Designer + + + + MSDiscoCodeGenerator + Reference.cs + + + Reference.map + + + Designer + + + Designer + + + Reference.map + + + Reference.map + + + MSDiscoCodeGenerator + Reference.cs + + + Designer + + + Designer + + + Designer + + + + Designer + + + Designer + + + + Designer + + + MSDiscoCodeGenerator + Reference.cs + + + Designer + + + Designer + + + Designer + + + Designer + + + Reference.map + + + Reference.map + + + Designer + + + Designer + + + + MSDiscoCodeGenerator + Reference.cs + + + + + Designer + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + Static + Web References\MSNWS.MSNABSharingService\ + http://msnp-sharp.googlecode.com/svn/branches/MSNPSHARP_31_STABLE/WebServiceDefAndSchemas/MSNABSharingService/msnab_sharingservice.wsdl + + + + + Settings + MSNPSharp_MSNWS_MSNABSharingService_SharingService + + + Static + Web References\MSNWS.MSNOIMStoreService\ + http://msnp-sharp.googlecode.com/svn/branches/MSNPSHARP_31_STABLE/WebServiceDefAndSchemas/MSNOIMStoreService/oim_ws.wsdl + + + + + Settings + MSNPSharp_MSNWS_MSNOIMStoreService_OIMStoreService + + + Static + Web References\MSNWS.MSNRSIService\ + http://msnp-sharp.googlecode.com/svn/branches/MSNPSHARP_31_STABLE/WebServiceDefAndSchemas/MSNRSIService/rsi_ws.wsdl + + + + + Settings + MSNPSharp_MSNWS_MSNRSIService_RSIService + + + Static + Web References\MSNWS.MSNSecurityTokenService\ + http://msnp-sharp.googlecode.com/svn/branches/MSNPSHARP_31_STABLE/WebServiceDefAndSchemas/MSNSecurityTokenService/ps.wsdl + + + + + Settings + MSNPSharp_MSNWS_MSNSecurityTokenService_SecurityTokenService + + + Static + Web References\MSNWS.MSNStorageService\ + http://msnp-sharp.googlecode.com/svn/branches/MSNPSHARP_31_STABLE/WebServiceDefAndSchemas/MSNStorageService/msnstorage_ws.wsdl + + + + + Settings + MSNPSharp_MSNWS_MSNStorageService_StorageService + + + + + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + Reference.map + + + + + + Reference.map + + + Designer + + + Reference.map + + + Reference.map + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/MSNPSharp/MSNPSharp.csproj.user b/MSNPSharp/MSNPSharp.csproj.user new file mode 100644 index 0000000..6f23531 --- /dev/null +++ b/MSNPSharp/MSNPSharp.csproj.user @@ -0,0 +1,13 @@ + + + + + + + + + + en-US + false + + \ No newline at end of file diff --git a/MSNPSharp/MSNPSharpException.cs b/MSNPSharp/MSNPSharpException.cs new file mode 100644 index 0000000..6807636 --- /dev/null +++ b/MSNPSharp/MSNPSharpException.cs @@ -0,0 +1,84 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Runtime.Serialization; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + /// + /// The base class for all MSNPSharp related exceptions + /// + [Serializable()] + public class MSNPSharpException : ApplicationException + { + /// + /// Basic constructor. + /// + public MSNPSharpException() + { + } + + /// + /// Specifies a general exception. + /// + /// A textual presentation of the exception message + public MSNPSharpException(string message) + : base(message) + { + } + + /// + /// Specifies a general exception but which originates from another exception. + /// + /// A textual presentation of the exception message + /// The (inner)exception which caused this exception. For example a SocketException. + public MSNPSharpException(string message, Exception innerException) + : base(message, innerException) + { + } + + /// + /// Serialization constructor. + /// + /// + /// + protected MSNPSharpException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + + } + } + +}; diff --git a/MSNPSharp/MailEventArgs.cs b/MSNPSharp/MailEventArgs.cs new file mode 100644 index 0000000..825f49c --- /dev/null +++ b/MSNPSharp/MailEventArgs.cs @@ -0,0 +1,439 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Net; +using System.Text.RegularExpressions; +using System.Text; +using System.Diagnostics; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + /// + /// Send as event argument when the server has send a (initial) mailbox status. + /// + [Serializable()] + public class MailboxStatusEventArgs : EventArgs + { + /// + /// Number of mails in the inbox which are unread + /// + public int InboxUnread + { + get + { + return inboxUnread; + } + set + { + inboxUnread = value; + } + } + + /// + /// + private int inboxUnread; + + /// + /// Number of folders which are unread + /// + public int FoldersUnread + { + get + { + return foldersUnread; + } + set + { + foldersUnread = value; + } + } + + /// + /// + private int foldersUnread; + + /// + /// The URL to go directly to the inbox of the contactlist owner + /// + public string InboxURL + { + get + { + return inboxURL; + } + set + { + inboxURL = value; + } + } + + /// + /// + private string inboxURL; + + /// + /// The URL to go directly to the folders of the contactlist owner + /// + public string FoldersURL + { + get + { + return foldersURL; + } + set + { + foldersURL = value; + } + } + + /// + /// + private string foldersURL; + + /// + /// The URL to go directly to the webpage to compose a new mail + /// + public string PostURL + { + get + { + return postURL; + } + set + { + postURL = value; + } + } + + /// + /// + private string postURL; + + /// + /// Constructory. + /// + /// + /// + /// + /// + /// + public MailboxStatusEventArgs(int inboxUnread, int foldersUnread, string inboxURL, string foldersURL, string postURL) + { + InboxUnread = inboxUnread; + FoldersUnread = foldersUnread; + InboxURL = inboxURL; + FoldersURL = foldersURL; + PostURL = postURL; + } + } + + /// + /// Send as event argument when unread mail has been read or the owner moves mail. + /// + [Serializable()] + public class MailChangedEventArgs : EventArgs + { + /// + /// The source folder the mail(s) are moved from + /// + public string SourceFolder + { + get + { + return sourceFolder; + } + set + { + sourceFolder = value; + } + } + + /// + /// + private string sourceFolder; + + /// + /// The destination folder the mail(s) are moved to + /// + public string DestinationFolder + { + get + { + return destinationFolder; + } + set + { + destinationFolder = value; + } + } + + /// + /// + private string destinationFolder; + + /// + /// The number of mails moved + /// + public int Count + { + get + { + return count; + } + set + { + count = value; + } + } + + /// + /// + private int count; + + /// + /// Indicates whether mails are moved between folders or if unread mails are read. + /// When sourcefolder and destination folder are the same this means the mails are not moved but read, and MailsRead will return true. Otherwise it will return false. + /// + public bool MailsAreRead + { + get + { + return SourceFolder == DestinationFolder; + } + } + + /// + /// Constructor, mainly used internal by the library. + /// + /// + /// + /// + public MailChangedEventArgs(string sourceFolder, string destinationFolder, int count) + { + SourceFolder = sourceFolder; + DestinationFolder = destinationFolder; + Count = count; + } + } + + /// + /// Send as event argument when the server notifies us of a new e-mail waiting. + /// + [Serializable()] + public class NewMailEventArgs : EventArgs + { + /// + /// The person's name who sended the e-mail + /// + public string From + { + get + { + return from; + } + set + { + try + { + Regex senderReg = new Regex("=\\u003F(?.+)\\u003F(?.)\\u003F(?.+)\\u003F="); + if (senderReg.Match(value).Success) + { + string strencoding = senderReg.Match(value).Groups["encoding"].Value; + string strdecode = senderReg.Match(value).Groups["decoder"].Value; + string encodedfrom = senderReg.Match(value).Groups["from"].Value; + Encoding encode = Encoding.GetEncoding(strencoding); + byte[] bytfrom = null; + if (strdecode.ToLowerInvariant() == "b") + { + bytfrom = Convert.FromBase64String(encodedfrom); + from = encode.GetString(bytfrom); + return; + } + if (strdecode.ToLowerInvariant() == "q") + { + //I GUSS this can work. + from = MSNHttpUtility.QPDecode(encodedfrom, encode); + return; + } + } + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, ex.Message, GetType().Name); + } + from = value; + } + } + + /// + /// + private string from; + + /// + /// The url to directly view the message in Hotmail + /// + public string MessageUrl + { + get + { + return messageUrl; + } + set + { + messageUrl = value; + } + } + + /// + /// + private string messageUrl; + + /// + /// The post url used for automatic hotmail login + /// + public string PostUrl + { + get + { + return postUrl; + } + set + { + postUrl = value; + } + } + + /// + /// + private string postUrl; + + /// + /// The subject of the e-mail + /// + public string Subject + { + get + { + return subject; + } + set + { + subject = value; + } + } + + /// + /// + private string subject; + + /// + /// The folder the mail is redirected to + /// + public string DestinationFolder + { + get + { + return destinationFolder; + } + set + { + destinationFolder = value; + } + } + + /// + /// + private string destinationFolder; + + /// + /// The e-mail adress of the person who sended the e-mail + /// + public string FromEmail + { + get + { + return fromEmail; + } + set + { + fromEmail = value; + } + } + + /// + /// + private string fromEmail; + + /// + /// ID of the message, used for hotmail login + /// + public int Id + { + get + { + return id; + } + set + { + id = value; + } + } + + /// + /// + private int id; + + /// + /// Constructor. + /// + /// + /// + /// + /// + /// + /// + /// + public NewMailEventArgs(string from, string messageUrl, string postUrl, string subject, string destinationFolder, string fromEmail, int id) + { + From = from; + PostUrl = postUrl; + MessageUrl = messageUrl; + Subject = subject; + DestinationFolder = destinationFolder; + FromEmail = fromEmail; + Id = id; + } + } +}; diff --git a/MSNPSharp/MessageManager.cs b/MSNPSharp/MessageManager.cs new file mode 100644 index 0000000..627ad1d --- /dev/null +++ b/MSNPSharp/MessageManager.cs @@ -0,0 +1,793 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace MSNPSharp.Utilities +{ + public class MessageManager : IDisposable + { + #region Events + + /// + /// Fired when a user message arrived. Use MessageType property to determine what kind of message it is. + /// + public event EventHandler MessageArrived; + + #endregion + + #region Fields and Properties + + private Dictionary conversationIndex = new Dictionary(100, new ConversationIDComparer()); + private Dictionary pendingConversations = new Dictionary(100, new ConversationIDComparer()); + private List conversations = new List(100); + + private Messenger messenger = null; + + /// + /// The instance this manager connected to. + /// + public Messenger Messenger + { + get { return messenger; } + } + + private object syncObject = new object(); + + protected object SyncObject + { + get { return syncObject; } + } + + + #endregion + + #region .ctor + + private MessageManager() + { + } + + /// + /// Constructor + /// + /// The instance this manager connected to. + public MessageManager(Messenger messenger) + { + this.messenger = messenger; + Messenger.ConversationCreated += new EventHandler(ConversationCreated); + Messenger.Nameserver.CrossNetworkMessageReceived += new EventHandler(CrossNetworkMessageReceived); + Messenger.Nameserver.MobileMessageReceived += new EventHandler(CrossNetworkMessageReceived); + } + + #endregion + + #region Event handlers + + private void ConversationCreated(object sender, ConversationCreatedEventArgs e) + { + // We do not listen to ContactJoin event. If a conversation has no text/typing/nudge/emoticon message + // arrived, this conversation will only be placed into conversation list. + AttatchEvents(e.Conversation); + AddConversationToConversationList(e.Conversation); + } + + private void ConversationEnded(object sender, ConversationEndEventArgs e) + { + DetatchEvents(e.Conversation); + RemoveConversationFromConversationIndex(e.Conversation); + RemoveConversationFromConversationList(e.Conversation); + } + + private void CrossNetworkMessageReceived(object sender, CrossNetworkMessageEventArgs e) + { + ConversationID id = ProcessArrivedConversation(new ConversationID(e.From)); + + switch (e.MessageType) + { + case NetworkMessageType.Typing: + case NetworkMessageType.Nudge: + OnMessageArrived(new MessageArrivedEventArgs(id, e.From, e.MessageType)); + break; + case NetworkMessageType.Text: + OnMessageArrived(new TextMessageArrivedEventArgs(id, e.From, e.Message as TextMessage)); + break; + } + + } + + private void PassportMemberUserTyping(object sender, ContactEventArgs e) + { + ConversationID id = ProcessArrivedConversation(new ConversationID(sender as Conversation)); + OnMessageArrived(new MessageArrivedEventArgs(id, e.Contact, NetworkMessageType.Typing)); + } + + private void PassportMemberTextMessageReceived(object sender, TextMessageEventArgs e) + { + ConversationID id = ProcessArrivedConversation(new ConversationID(sender as Conversation)); + OnMessageArrived(new TextMessageArrivedEventArgs(id, e.Sender, e.Message)); + } + + private void PassportMemberNudgeReceived(object sender, ContactEventArgs e) + { + ConversationID id = ProcessArrivedConversation(new ConversationID(sender as Conversation)); + OnMessageArrived(new MessageArrivedEventArgs(id, e.Contact, NetworkMessageType.Nudge)); + } + + private void PassportMemberMSNObjectDataTransferCompleted(object sender, ConversationMSNObjectDataTransferCompletedEventArgs e) + { + ConversationID id = ProcessArrivedConversation(new ConversationID(sender as Conversation)); + if (e.ClientData is Emoticon) + { + Emoticon emoticon = e.ClientData as Emoticon; + OnMessageArrived(new EmoticonArrivedEventArgs(id, e.RemoteContact, emoticon)); + } + } + + #endregion + + protected virtual void OnMessageArrived(MessageArrivedEventArgs e) + { + if (MessageArrived != null) + MessageArrived(this, e); + } + + private ConversationID ProcessArrivedConversation(ConversationID cId) + { + lock (SyncObject) + { + bool created = HasConversation(cId); + bool pending = IsPendingConversation(cId); + if (pending) + { + if (!created) + { + AddConversationToConversationIndex(cId, cId.Conversation); //We fix this bug. + } + + if (created) + { + //What happends?! + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[ProcessArrivedConversation Error]: A conversation is both in pending and created status."); + + } + + RemovePendingConversation(cId); + } + + if (!pending) + { + if (!created) + { + AddConversationToConversationIndex(cId, cId.Conversation); + } + } + + return cId; + } + } + + private bool HasConversation(ConversationID cId) + { + lock (syncObject) + return conversationIndex.ContainsKey(cId); + } + + private bool IsPendingConversation(ConversationID cId) + { + lock (SyncObject) + { + return pendingConversations.ContainsKey(cId); + } + } + + /// + /// Add the specific object into conversatoin list. And listen to its message events (i.e. user typing messages, text messages). + /// + /// + /// + /// Return true if added successfully, false if the conversation with the specific id already exists. + private bool AddConversationToConversationIndex(ConversationID id, Conversation conversation) + { + lock (SyncObject) + { + if (conversationIndex.ContainsKey(id)) + return false; + conversationIndex[id] = conversation; + return true; + } + } + + private void AddConversationToConversationList(Conversation conversation) + { + lock (SyncObject) + { + conversations.Add(conversation); + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "A new conversation has been added into conversation list, " + + "current conversation count: " + conversations.Count + "."); + } + } + + private void AddPending(ConversationID cId, Contact remoteOwner) + { + lock (SyncObject) + { + pendingConversations[cId] = remoteOwner; + } + } + + private bool RemovePendingConversation(ConversationID cId) + { + lock (SyncObject) + { + if (IsPendingConversation(cId)) + { + pendingConversations.Remove(cId); + return true; + } + else + { + return false; + } + } + } + + private bool RemoveConversationFromConversationIndex(ConversationID cId) + { + lock (SyncObject) + { + if (conversationIndex.ContainsKey(cId)) + { + conversationIndex.Remove(cId); + return true; + } + else + { + return false; + } + } + } + + private bool RemoveConversationFromConversationIndex(Conversation conversation) + { + lock (SyncObject) + { + Dictionary cp = new Dictionary(conversationIndex, new ConversationIDComparer()); + foreach (ConversationID id in cp.Keys) + { + if (object.ReferenceEquals(cp[id], conversation)) + { + conversationIndex.Remove(id); + return true; + } + } + + return false; + } + } + + private bool RemoveConversationFromConversationList(Conversation conversation) + { + lock (SyncObject) + { + bool returnValue = conversations.Remove(conversation); + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "A conversation has been removed, there is/are " + + conversations.Count + " conversation(s) in conversation list."); + return returnValue; + } + } + + private void DetatchEvents(Conversation conversation) + { + if (conversation != null) + { + conversation.TextMessageReceived -= PassportMemberTextMessageReceived; + conversation.NudgeReceived -= PassportMemberNudgeReceived; + conversation.UserTyping -= PassportMemberUserTyping; + conversation.ConversationEnded -= ConversationEnded; + conversation.MSNObjectDataTransferCompleted -= PassportMemberMSNObjectDataTransferCompleted; + } + } + + private void AttatchEvents(Conversation conversation) + { + DetatchEvents(conversation); + + conversation.TextMessageReceived += new EventHandler(PassportMemberTextMessageReceived); + conversation.NudgeReceived += new EventHandler(PassportMemberNudgeReceived); + conversation.UserTyping += new EventHandler(PassportMemberUserTyping); + conversation.ConversationEnded += new EventHandler(ConversationEnded); + conversation.MSNObjectDataTransferCompleted += new EventHandler(PassportMemberMSNObjectDataTransferCompleted); + } + + + /// + /// Test whether the conntected to this manager is still in signed in status. + /// + /// Messenger not sign in. + private void CheckMessengerStatus() + { + if (!Messenger.Nameserver.IsSignedIn) + { + throw new InvalidOperationException("Messenger not sign in. Please sign in first."); + } + } + + /// + /// Test whether a contact can be the receiver of a user message. + /// + /// + /// + /// The target is not a messenger contact. + /// The message is not compatible to the specific contact. + private void CheckContact(Contact messengerContact, MessageObject messageObject) + { + if (!messengerContact.IsMessengerUser && !messengerContact.NSMessageHandler.BotMode) + { + throw new MSNPSharpException("This is not a MSN contact."); + } + + if (messengerContact.ClientType == ClientType.EmailMember && (messageObject is EmoticonObject)) + { + throw new NotSupportedException("A Yahoo Messenger contact cannot receive custom emoticon."); + } + + if ((messengerContact.ClientType == ClientType.PhoneMember || messengerContact.MobileAccess) && (messageObject is EmoticonObject || messageObject is NudgeObject || messageObject is UserTypingObject)) + { + throw new NotSupportedException("A Phone Contact cannot receive " + messageObject.GetType().ToString() + " messages."); + } + + if (messengerContact.Status == PresenceStatus.Offline && (messageObject is TextMessageObject) == false) + { + throw new NotSupportedException("The specific message cannot send to an offline contact: " + messengerContact); + } + } + + /// + /// Send a cross network message to Yahoo! Messenger network + /// + /// + /// + /// + /// Throw when sending a custom emoticon to a Yahoo Messenger contact. + private void SendYIMMessage(Contact yimContact, MessageObject messageObject) + { + if (yimContact.IsMessengerUser && yimContact.ClientType == ClientType.EmailMember) + { + if (messageObject is EmoticonObject) + { + throw new InvalidOperationException("Cannot send custom emoticon to a Email messenger contact."); + } + + try + { + + if (messageObject is NudgeObject) + { + Messenger.Nameserver.SendCrossNetworkMessage(yimContact, NetworkMessageType.Nudge); + } + + if (messageObject is UserTypingObject) + { + Messenger.Nameserver.SendCrossNetworkMessage(yimContact, NetworkMessageType.Typing); + } + + if (messageObject is TextMessageObject) + { + Messenger.Nameserver.SendCrossNetworkMessage(yimContact, messageObject.InnerObject as TextMessage); + } + + } + + catch (Exception ex) + { + throw ex; + } + } + else + { + throw new InvalidOperationException("Cannot send message to email contact: " + yimContact); + } + + } + + /// + /// Send a cross network message to Mobile Messenger. + /// + /// + /// + /// + /// Throw when sending a custom emoticon to a Yahoo Messenger contact. + private void SendMobileMessage(Contact mobileContact, MessageObject messageObject) + { + if (mobileContact.ClientType == ClientType.PhoneMember || mobileContact.MobileAccess) + { + if (messageObject is EmoticonObject || messageObject is NudgeObject || messageObject is TextMessageObject) + { + throw new InvalidOperationException("Cannot send a " + messageObject.GetType().ToString() + " to a Phone Contact."); + } + + try + { + Messenger.Nameserver.SendMobileMessage(mobileContact, (messageObject.InnerObject as TextMessage).Text); + + } + + catch (Exception ex) + { + throw ex; + } + } + else + { + throw new InvalidOperationException("Cannot send message to Phone Contact: " + mobileContact); + } + + } + + /// + /// Send the message through the specific + /// + /// + /// + /// Thrown when a conversation is already ended. + private void SendConversationMessage(Conversation conversation, MessageObject messageObject) + { + if (conversation.Ended) + throw new InvalidOperationException("Cannot send a message through an ended conversation."); + + try + { + if (messageObject is NudgeObject) + { + conversation.SendNudge(); + } + + if (messageObject is UserTypingObject) + { + conversation.SendTypingMessage(); + } + + if (messageObject is TextMessageObject) + { + conversation.SendTextMessage(messageObject.InnerObject as TextMessage); + } + + if (messageObject is EmoticonObject) + { + conversation.SendEmoticonDefinitions(messageObject.InnerObject as List, (messageObject as EmoticonObject).Type); + } + } + catch (Exception ex) + { + throw ex; + } + } + + /// + /// Send a message to a remote contact by all means. This method always send the message through a single chat conversation. + /// + /// + /// + /// The ID of conversation that send this message + private void SendMessage(Contact contact, MessageObject messageObject) + { + CheckMessengerStatus(); + + //Verify messenger contact. + CheckContact(contact, messageObject); + + //Process YIM contact. + if (contact.ClientType == ClientType.EmailMember) + { + SendYIMMessage(contact, messageObject); + return; + } + + if (contact.ClientType == ClientType.PhoneMember) + { + SendMobileMessage(contact, messageObject); + } + + //Process OIM. + if (contact.Status == PresenceStatus.Offline) + { + Messenger.Nameserver.OIMService.SendOIMMessage(contact, (messageObject as TextMessageObject).InnerObject as TextMessage); + return; + } + } + + /// + /// Send a message to the spcific conversation. + /// + /// + /// + /// Guid.Empty if conversatio has ended or not exists. + private ConversationID SendMessage(ConversationID cId, MessageObject messageObject) + { + if (cId == null) + { + throw new ArgumentNullException("cId is null."); + } + + //If the messenger is not signed in, this calling will throw an exception. + CheckMessengerStatus(); + + lock (SyncObject) + { + bool created = HasConversation(cId); + bool pending = IsPendingConversation(cId); + if (cId.NetworkType != ClientType.EmailMember) + { + if (cId.RemoteOwner.Status != PresenceStatus.Offline) + { + if ((!pending) && created) //Send message through exisiting conversations. + { + SendConversationMessage(GetConversation(cId), messageObject); + } + else + { + + //In the following case, the conversation object is not actually created. + //However, if the message is user typing, we just do nothing. + if (!(messageObject is UserTypingObject)) + { + cId = CreateNewConversation(cId); + CheckContact(cId.RemoteOwner, messageObject); + SendConversationMessage(cId.Conversation, messageObject); + } + } + } + else + { + if (!(messageObject is UserTypingObject)) //You cannot send typing messages as OIM messages. + { + RemovePendingConversation(cId); + //Verify messenger contact. + CheckContact(cId.RemoteOwner, messageObject); + SendMessage(cId.RemoteOwner, messageObject); + } + } + } + + if (cId.NetworkType == ClientType.EmailMember) //Yahoo! + { + CheckContact(cId.RemoteOwner, messageObject); + SendMessage(cId.RemoteOwner, messageObject); + RemovePendingConversation(cId); + } + } + return cId; + + } + + private ConversationID CreateNewConversation(ConversationID pendingId) + { + bool created = HasConversation(pendingId); + bool pending = IsPendingConversation(pendingId); + bool otherNetwork = (pendingId.RemoteOwner.ClientType != ClientType.PassportMember); + + if (pending) + RemovePendingConversation(pendingId); + if (created || otherNetwork) + return pendingId; + + pendingId.SetConversation(Messenger.CreateConversation()); + AddConversationToConversationIndex(pendingId, pendingId.Conversation); + pendingId.Conversation.Invite(pendingId.RemoteOwner); + + return pendingId; + + } + + #region Public methods + + /// + /// Get the corresponding conversation from conversation Id. + /// + /// + /// A conversation object will returned if found, null otherwise. + public Conversation GetConversation(ConversationID cId) + { + lock (SyncObject) + { + if (conversationIndex.ContainsKey(cId)) + return conversationIndex[cId]; + return null; + } + } + + public ConversationID SendTyping(ConversationID conversationID) + { + return SendMessage(conversationID, new UserTypingObject()); + } + + public ConversationID SendNudge(ConversationID conversationID) + { + return SendMessage(conversationID, new NudgeObject()); + } + + + public ConversationID SendTextMessage(ConversationID conversationID, TextMessage message) + { + return SendMessage(conversationID, new TextMessageObject(message)); + } + + + public ConversationID SendEmoticonDefinitions(ConversationID conversationID, List emoticons, EmoticonType icontype) + { + return SendMessage(conversationID, new EmoticonObject(emoticons, icontype)); + } + + public ConversationID GetID(Contact remoteOwner) + { + lock (SyncObject) + { + ConversationID id = new ConversationID(remoteOwner); + bool created = HasConversation(id); + bool pending = IsPendingConversation(id); + if (created || pending) + return id; + + AddPending(id, remoteOwner); + return id; + } + } + + /// + /// Invite another user to a conversation. + /// + /// + /// + /// The updated conversation Id. + /// The remote contact is not a + public ConversationID InviteContactToConversation(ConversationID conversationID, Contact remoteContact) + { + ConversationID cId = conversationID; + if (remoteContact.IsSibling(cId.RemoteOwner)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Connot invite the remote owner into this conversation again."); + return cId; + } + + if (remoteContact.ClientType != ClientType.PassportMember) + throw new InvalidOperationException("The remoteContact: " + remoteContact + " is not a PassportMember."); + + Conversation activeConversation = null; + if (HasConversation(cId)) + { + activeConversation = GetConversation(cId); + } + else + { + //The conversation object not exist, we need to create one first. + //Then invite the remote owner to the newly created conversation. + cId = CreateNewConversation(cId); + activeConversation = cId.Conversation; + } + + if (activeConversation.Ended) //If conversation exists, but ended. + { + //We dump the old conversation and start the whole process again. + RemoveConversationFromConversationIndex(activeConversation); + RemovePendingConversation(cId); + return InviteContactToConversation(cId, remoteContact); + } + + activeConversation.Invite(remoteContact); + + + return cId; + } + + /// + /// Invite another user to a conversation. + /// + /// + /// + /// The updated conversation Id. + /// The remote contact is not a + public ConversationID InviteContactToConversation(ConversationID conversationID, Contact[] contacts) + { + ConversationID cId = conversationID; + foreach (Contact contact in contacts) + { + cId = InviteContactToConversation(cId, contact); + } + + return cId; + } + + /// + /// End the specific conversation and release the resources it used. + /// + /// + public void EndConversation(ConversationID conversationId) + { + ConversationID cId = conversationId; + bool created = HasConversation(cId); + bool pending = IsPendingConversation(cId); + + if (pending) + RemovePendingConversation(cId); + + if (created) + { + if (cId.NetworkType == ClientType.PassportMember) //Only passport conversation contains a conversation object. Other conversation, like Yahoo does not. + { + List overflowConversations = new List(10); + lock (SyncObject) + { + foreach (Conversation conversation in conversations) + { + if (cId == new ConversationID(conversation)) + { + overflowConversations.Add(conversation); + } + } + } + + foreach (Conversation conversation in overflowConversations) + { + conversation.End(); + } + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "A none Passprt Member conversation has been removed from the conversation index"); + } + RemoveConversationFromConversationIndex(cId); + } + } + + #endregion + + #region IDisposable Ա + + public void Dispose() + { + if (Messenger != null) + { + Messenger.ConversationCreated -= ConversationCreated; + Messenger.Nameserver.CrossNetworkMessageReceived -= CrossNetworkMessageReceived; + Messenger.Nameserver.MobileMessageReceived -= CrossNetworkMessageReceived; + } + + } + + #endregion + } +} diff --git a/MSNPSharp/MessageManagerEventArgs.cs b/MSNPSharp/MessageManagerEventArgs.cs new file mode 100644 index 0000000..79092ab --- /dev/null +++ b/MSNPSharp/MessageManagerEventArgs.cs @@ -0,0 +1,120 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace MSNPSharp.Utilities +{ + + public class MessageArrivedEventArgs : EventArgs + { + private ConversationID conversationID = null; + + /// + /// The identifier of a in . + /// + public ConversationID ConversationID + { + get { return conversationID; } + } + + private Contact sender = null; + + /// + /// The sender of message. + /// + public Contact Sender + { + get { return sender; } + } + + private NetworkMessageType messageType = NetworkMessageType.None; + + /// + /// The type of message received. + /// + public NetworkMessageType MessageType + { + get { return messageType; } + } + + + public MessageArrivedEventArgs(ConversationID conversationId, Contact sender, NetworkMessageType type) + { + conversationID = conversationId; + this.sender = sender; + messageType = type; + } + } + + public class TextMessageArrivedEventArgs : MessageArrivedEventArgs + { + private TextMessage textMessage = null; + + /// + /// The text message received. + /// + public TextMessage TextMessage + { + get { return textMessage; } + } + + + public TextMessageArrivedEventArgs(ConversationID conversationId, Contact sender, TextMessage textMessage) + : base(conversationId, sender, NetworkMessageType.Text) + { + this.textMessage = textMessage; + } + } + + public class EmoticonArrivedEventArgs : MessageArrivedEventArgs + { + private Emoticon emoticon = null; + + /// + /// The emoicon data received. + /// + public Emoticon Emoticon + { + get { return emoticon; } + } + + public EmoticonArrivedEventArgs(ConversationID conversationId, Contact sender, Emoticon emoticon) + : base(conversationId, sender, NetworkMessageType.Emoticon) + { + this.emoticon = emoticon; + } + + } +} diff --git a/MSNPSharp/Messenger.cs b/MSNPSharp/Messenger.cs new file mode 100644 index 0000000..fbda4cc --- /dev/null +++ b/MSNPSharp/Messenger.cs @@ -0,0 +1,501 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Collections; +using System.Diagnostics; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + using MSNPSharp.DataTransfer; + using MSNPSharp.Utilities; + + #region ConversationCreatedEvent + + /// + /// Used when a new switchboard session is created. + /// + public class ConversationCreatedEventArgs : EventArgs + { + private object _initiator; + private Conversation _conversation; + + /// + /// The affected conversation + /// + public Conversation Conversation + { + get + { + return _conversation; + } + set + { + _conversation = value; + } + } + + /// + /// The object that requested the switchboard. Null if the conversation was initiated by a + /// remote client. + /// + public object Initiator + { + get + { + return _initiator; + } + set + { + _initiator = value; + } + } + + /// + /// Constructor. + /// + public ConversationCreatedEventArgs(Conversation conversation, object initiator) + { + _conversation = conversation; + _initiator = initiator; + } + } + + #endregion + + /// + /// Provides an easy interface for the client programmer. + /// + /// + /// Messenger is an important class for the client programmer. It provides an + /// easy interface to communicate with the network. Messenger is a facade which hides all + /// lower abstractions like message processors, protocol handlers, etc. + /// Messenger passes through events from underlying objects. This way the client programmer + /// can connect eventhandlers just once. + /// + public class Messenger + { + #region Events + + /// + /// Occurs when a new conversation is created. Either by a local or remote invitation. + /// + /// + /// You can check the initiator object in the event arguments to see which party initiated the + /// conversation. This event is called after the messenger server has created a switchboard handler, + /// so there is always a valid messageprocessor. + /// + public event EventHandler ConversationCreated; + + /// + /// Occurs when a remote client has send an invitation for a filetransfer session. + /// + public event EventHandler TransferInvitationReceived; + + internal void OnTransferInvitationReceived(object sender, MSNSLPInvitationEventArgs args) + { + if (TransferInvitationReceived != null) + TransferInvitationReceived(sender, args); + } + + protected virtual void OnConversationCreated(Conversation conversation, object initiator) + { + if (ConversationCreated != null) + ConversationCreated(this, new ConversationCreatedEventArgs(conversation, initiator)); + } + + #endregion + + #region Members + + private NSMessageProcessor nsMessageProcessor = null; + private NSMessageHandler nsMessageHandler = null; + private ConnectivitySettings connectivitySettings = null; + private Credentials credentials = new Credentials(MsnProtocol.MSNP18); + private ArrayList conversations = ArrayList.Synchronized(new ArrayList()); + private MessageManager messageManager = null; + private bool shouldReconnect = false; + + #endregion + + #region .ctor + + /// + /// Basic constructor to instantiate a Messenger object. + /// + public Messenger() + { + connectivitySettings = new ConnectivitySettings(); + nsMessageProcessor = new NSMessageProcessor(connectivitySettings); + nsMessageHandler = new NSMessageHandler(this); + messageManager = new MessageManager(this); + + Nameserver.SBCreated += delegate(object sender, SBCreatedEventArgs ce) + { + // check if the request is remote or on our initiative + if (ce.Initiator != null) + { + return; + } + + // create a conversation object to handle with the switchboard + Conversation c = new Conversation(this, ce.Switchboard); + OnConversationCreated(c, ce.Initiator); + return; + }; + + NameserverProcessor.ConnectionClosed += new EventHandler(NameserverProcessor_ConnectionClosed); + } + + + + #endregion + + #region Properties + + /// + /// Provide a simple way to send and receive messages. + /// + public MessageManager MessageManager + { + get + { + return messageManager; + } + } + + /// + /// The message processor that is used to send and receive nameserver messages. + /// + /// + /// This processor is mainly used by the nameserver handler. + /// + public NSMessageProcessor NameserverProcessor + { + get + { + return nsMessageProcessor; + } + } + + /// + /// Specifies the connection capabilities of the local machine. + /// + /// + /// Use this property to set specific connectivity settings like proxy servers and custom messenger servers. + /// + public ConnectivitySettings ConnectivitySettings + { + get + { + return connectivitySettings; + } + set + { + connectivitySettings = value; + NameserverProcessor.ConnectivitySettings = ConnectivitySettings; + } + } + + /// + /// The credentials which identify the messenger account and the client authentication. + /// + /// + /// This property must be set before logging in the messenger service. Both the account + /// properties and the client identifier codes must be set. The first, the account, specifies the + /// account which represents the local user, for example 'account@hotmail.com'. The second, the + /// client codes, specifies how this client will authenticate itself against the messenger server. + /// See for more information about this. + /// + public Credentials Credentials + { + get + { + return credentials; + } + set + { + credentials = value; + } + } + + /// + /// The message handler that is used to handle incoming nameserver messages. + /// + public NSMessageHandler Nameserver + { + get + { + return nsMessageHandler; + } + } + + /// + /// Returns whether there is a connection with the messenger server. + /// + public bool Connected + { + get + { + return nsMessageProcessor.Connected; + } + } + + /// + /// A list of all contacts. + /// + public ContactList ContactList + { + get + { + return Nameserver.ContactList; + } + } + + /// + /// A list of all contactgroups. + /// + public ContactGroupList ContactGroups + { + get + { + return Nameserver.ContactGroups; + } + } + + /// + /// A collection of all circles which are defined by the user who logged into the messenger network. + /// + public CircleList CircleList + { + get + { + return Nameserver.CircleList; + } + } + + /// + /// Offline message service. + /// + public OIMService OIMService + { + get + { + return Nameserver.OIMService; + } + } + + /// + /// Storage service to get/update display name, personal status, display picture etc. + /// + public MSNStorageService StorageService + { + get + { + return Nameserver.StorageService; + } + } + + /// + /// What's Up service + /// + public WhatsUpService WhatsUpService + { + get + { + return Nameserver.WhatsUpService; + } + } + + /// + /// Contact service. + /// + public ContactService ContactService + { + get + { + return Nameserver.ContactService; + } + } + + /// + /// The local user logged into the network. It will remain null until user successfully login. + /// + public Owner Owner + { + get + { + return Nameserver.ContactList.Owner; + } + } + + /// + /// The handler that handles all incoming P2P framework messages. + /// + public P2PHandler P2PHandler + { + get + { + return Nameserver.P2PHandler; + } + } + + public ArrayList Conversations + { + get + { + return conversations; + } + } + + #endregion + + #region Methods + + private void DoConnect() + { + NameserverProcessor.ConnectivitySettings = connectivitySettings; + NameserverProcessor.RegisterHandler(nsMessageHandler); + Nameserver.MessageProcessor = NameserverProcessor; + Nameserver.Credentials = credentials; + + NameserverProcessor.Connect(); + } + + private void NameserverProcessor_ConnectionClosed(object sender, EventArgs e) + { + if (shouldReconnect) + { + shouldReconnect = false; + DoConnect(); + + } + } + + /// + /// Connect to the messenger network. + /// + public virtual void Connect() + { + if (NameserverProcessor == null) + throw new MSNPSharpException("No message processor defined"); + + if (Nameserver == null) + throw new MSNPSharpException("No message handler defined"); + + if (Credentials == null) + throw new MSNPSharpException("No credentials defined"); + + if (Credentials.Account.Length == 0) + throw new MSNPSharpException("The specified account is empty"); + + if (Credentials.Password.Length == 0) + throw new MSNPSharpException("The specified password is empty"); + + if (Credentials.ClientCode.Length == 0 || credentials.ClientID.Length == 0) + throw new MSNPSharpException("The local messengerclient credentials (client-id and client code) are not specified. This is necessary in order to authenticate the local client with the messenger server. See for more info about the values to use the documentation of the Credentials class."); + + if (NameserverProcessor.Connected) + { + shouldReconnect = true; + Disconnect(); + } + else + { + // everything is okay, resume + DoConnect(); + } + } + + /// + /// Disconnect from the messenger network. + /// + public virtual void Disconnect() + { + if (NameserverProcessor.Connected) + { + if (nsMessageHandler != null && Nameserver.ContactList.Owner != null) + { + Nameserver.ContactList.Owner.SetStatus(PresenceStatus.Offline); + } + + NameserverProcessor.Disconnect(); + } + } + + /// + /// Creates a conversation. + /// + /// + /// This method will fire the event. The initiator object of the created switchboard will be this messenger object. + /// + /// + public Conversation CreateConversation() + { + Conversation conversation = new Conversation(this); + OnConversationCreated(conversation, this); + return conversation; + } + + + /// + /// Returns a MSNSLPHandler, associated with a P2P session. The returned object can be used to send + /// or receive invitations from the remote contact. + /// + /// + /// + public MSNSLPHandler GetMSNSLPHandler(Contact remoteContact) + { + if (!Nameserver.ContactList.HasContact(remoteContact.Mail, remoteContact.ClientType)) + throw new MSNPSharpException("Function not supported. Only MSN user can create a P2P session."); + + P2PMessageSession p2pSession = nsMessageHandler.P2PHandler.GetSession(Nameserver.ContactList.Owner, Nameserver.ContactList.Owner.MachineGuid, remoteContact, remoteContact.SelectRandomEPID()); + return p2pSession.MasterSession; + } + + public P2PTransferSession SendFile(Contact remoteContact, string filename, FileStream fileStream) + { + MSNSLPHandler msnslpHandler = GetMSNSLPHandler(remoteContact); + return msnslpHandler.SendInvitation(Owner, remoteContact, Path.GetFileName(filename), fileStream); + } + + public P2PTransferSession RequestMsnObject(Contact remoteContact, MSNObject msnObject) + { + MSNSLPHandler msnslpHandler = GetMSNSLPHandler(remoteContact); + return msnslpHandler.SendInvitation(Owner, remoteContact, msnObject); + } + + #endregion + } +}; diff --git a/MSNPSharp/MobileMessage.cs b/MSNPSharp/MobileMessage.cs new file mode 100644 index 0000000..b891be7 --- /dev/null +++ b/MSNPSharp/MobileMessage.cs @@ -0,0 +1,197 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Text; +using System.Xml; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + /// + /// Message that is send to a mobile device. + /// + public class MobileMessage : MSNMessage + { + #region Private + private string callbackNumber = String.Empty; + private string callbackDeviceName = String.Empty; + private string text = String.Empty; + private string receiver = String.Empty; + #endregion + + #region Public + + /// + /// The telephone number that the remote contact will see. + /// + public string CallbackNumber + { + get + { + return callbackNumber; + } + set + { + callbackNumber = value; + } + } + + /// + /// The telephone device type that the remote contact will see. (e.g. "Homephone", "Work phone") + /// + public string CallbackDeviceName + { + get + { + return callbackDeviceName; + } + set + { + callbackDeviceName = value; + } + } + + /// + /// The text that will be send to the remote contact. + /// + public string Text + { + get + { + return text; + } + set + { + text = value; + } + } + + /// + /// The account of the remote contact. + /// + public string Receiver + { + get + { + return receiver; + } + set + { + receiver = value; + } + } + #endregion + + /// + /// + /// + public MobileMessage() + { + } + + /// + /// Throws an exception. + /// + /// + public override void ParseBytes(byte[] data) + { + throw new MSNPSharpException("MobileMessage can not parse data. This is done via a notification document."); + } + + /// + /// Returns the XML formatted message that represents the mobile message. + /// + /// + public override byte[] GetBytes() + { + MemoryStream memStream = new MemoryStream(); + + XmlTextWriter writer = new XmlTextWriter(memStream, new System.Text.UTF8Encoding(false)); + + writer.Formatting = Formatting.None; + writer.Indentation = 0; + writer.IndentChar = ' '; + + // check whether there is a call back number set + if (callbackNumber.Length > 0) + { + writer.WriteStartElement("PHONE"); + writer.WriteAttributeString("pri", "1"); + writer.WriteStartElement("LOC"); + + writer.WriteString(callbackDeviceName); + writer.WriteEndElement(); + writer.WriteStartElement("NUM"); + writer.WriteString(callbackNumber); + writer.WriteEndElement(); + writer.WriteEndElement(); + } + + if (Text.Length > 113) + throw new MSNPSharpException("Mobile text message too long. A maximum of 113 characters is allowed."); + + writer.WriteRaw(""); + writer.WriteString(text); + writer.WriteRaw(""); + writer.Flush(); + + return memStream.ToArray(); + } + + /// + /// Sets the command and commandvalues of the parent. + /// + public override void PrepareMessage() + { + base.PrepareMessage(); + if (ParentMessage != null && ParentMessage is MSNMessage) + { + ((MSNMessage)ParentMessage).Command = "PGD"; + ((MSNMessage)ParentMessage).CommandValues.Add(Receiver); + ((MSNMessage)ParentMessage).CommandValues.Add("1"); + } + } + + /// + /// Returns the XML formatted body. + /// + /// + public override string ToString() + { + return "[MobileMessage]" + System.Text.Encoding.UTF8.GetString(this.GetBytes()); + } + + } +}; diff --git a/MSNPSharp/NSMessageHandler.Obsolete.cs b/MSNPSharp/NSMessageHandler.Obsolete.cs new file mode 100644 index 0000000..79e8538 --- /dev/null +++ b/MSNPSharp/NSMessageHandler.Obsolete.cs @@ -0,0 +1,70 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Net; +using System.Web; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + partial class NSMessageHandler + { + + /// + /// The owner of the contactlist. This is the identity that logged into the messenger network. + /// + [Obsolete(@"Obsoleted in 3.1, please use Messenger.Owner instead. + The Owner property's behavior changed a little. + It will remain null until user successfully login. + You may need to change your code if you see this notice. + For more information and example, please refer to the example client.", true)] + public Owner Owner + { + get + { + return ContactList.Owner; + } + } + + [Obsolete("MSNP18 no more supported", true)] + protected virtual void OnILNReceived(NSMessage message) + { + } + + [Obsolete("MSNP18 no more supported", true)] + protected virtual void OnBPRReceived(NSMessage message) + { + } + } +}; diff --git a/MSNPSharp/NSMessageHandler.cs b/MSNPSharp/NSMessageHandler.cs new file mode 100644 index 0000000..4af46fe --- /dev/null +++ b/MSNPSharp/NSMessageHandler.cs @@ -0,0 +1,3872 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Net; +using System.Web; +using System.Xml; +using System.Text; +using System.Threading; +using System.Collections; +using System.Diagnostics; +using System.Globalization; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + using MSNPSharp.DataTransfer; + + /// + /// Handles the protocol messages from the notification server + /// and implements protocol version MSNP18. + /// + public partial class NSMessageHandler : IMessageHandler + { + public static readonly Guid MachineGuid = Guid.NewGuid(); + + #region Members + + private Credentials credentials = new Credentials(MsnProtocol.MSNP18); + private SocketMessageProcessor messageProcessor = null; + private IPEndPoint externalEndPoint = null; + private P2PHandler p2pHandler = null; + private Messenger messenger = null; + + private CircleList circleList = null; + private ContactGroupList contactGroups = null; + private ContactList contactList = null; + private ContactManager manager = null; + private bool autoSynchronize = true; + private bool botMode = false; + private int canSendPing = 1; + + private bool isSignedIn = false; + private MSNTicket msnticket = MSNTicket.Empty; + private Queue pendingSwitchboards = new Queue(); + + private ContactService contactService = null; + private OIMService oimService = null; + private MSNStorageService storageService = null; + private WhatsUpService whatsUpService = null; + + private List censorWords = new List(0); + private Dictionary sessions = new Dictionary(0); + private Guid p2pInviteSchedulerId = Guid.Empty; + private Guid sbRequestSchedulerId = Guid.Empty; + + protected internal NSMessageHandler(Messenger parentMessenger) + { + circleList = new CircleList(this); + contactGroups = new ContactGroupList(this); + contactList = new ContactList(this); + manager = new ContactManager(this); + + contactService = new ContactService(this); + oimService = new OIMService(this); + storageService = new MSNStorageService(this); + whatsUpService = new WhatsUpService(this); + + p2pHandler = new P2PHandler(this, parentMessenger); + + messenger = parentMessenger; + } + + #endregion + + #region Properties + + /// + /// The library runs as a bot. Not to auto synchronize the addressbook when login. + /// + public bool BotMode + { + get + { + return botMode; + } + set + { + botMode = value; + AutoSynchronize = !value; + } + } + + + public bool AutoSynchronize + { + get + { + return autoSynchronize; + } + set + { + autoSynchronize = value; + } + } + + /// + /// Defines whether the user is signed in the messenger network + /// + public bool IsSignedIn + { + get + { + return isSignedIn; + } + } + + /// + /// Keep track whether a address book synchronization has been completed so we can warn the client programmer + /// + public bool AddressBookSynchronized + { + get + { + return ContactService.AddressBookSynchronized; + } + } + + /// + /// The end point as perceived by the server. This is set after the owner's profile is received. + /// + public IPEndPoint ExternalEndPoint + { + get + { + return externalEndPoint; + } + } + + /// + /// A collection of all contacts which are on any of the lists of the person who logged into the messenger network + /// + public ContactList ContactList + { + get + { + return contactList; + } + } + + /// + /// Censors that cannot contain in text messages. + /// + public List CensorWords + { + get + { + return censorWords; + } + } + + /// + /// A collection of all contactgroups which are defined by the user who logged into the messenger network. + /// + public ContactGroupList ContactGroups + { + get + { + return contactGroups; + } + } + + /// + /// A collection of all circles which are defined by the user who logged into the messenger network. + /// + public CircleList CircleList + { + get + { + return circleList; + } + } + + /// + /// These credentials are used for user authentication and client identification + /// + public Credentials Credentials + { + get + { + return credentials; + } + set + { + credentials = value; + } + } + + /// + /// If WebProxy is set the Webproxy is used for the + /// authentication with Passport.com + /// + public ConnectivitySettings ConnectivitySettings + { + get + { + return (MessageProcessor as NSMessageProcessor).ConnectivitySettings; + } + } + + /// + /// A service that provide contact operations. + /// + internal ContactService ContactService + { + get + { + return contactService; + } + } + + /// + /// Offline message service. + /// + internal OIMService OIMService + { + get + { + return oimService; + } + } + + /// + /// Storage Service for get/update display name, personal status, display picture etc. + /// + internal MSNStorageService StorageService + { + get + { + return storageService; + } + } + + internal WhatsUpService WhatsUpService + { + get + { + return whatsUpService; + } + } + + /// + /// The processor to handle the messages + /// + public IMessageProcessor MessageProcessor + { + get + { + return messageProcessor; + } + set + { + // de-register from the previous message processor + if (messageProcessor != null) + { + messageProcessor.ConnectionEstablished -= OnProcessorConnectCallback; + messageProcessor.ConnectionClosed -= OnProcessorDisconnectCallback; + } + + messageProcessor = value as SocketMessageProcessor; + + if (messageProcessor != null) + { + // catch the connect event so we can start sending the USR command upon initiating + messageProcessor.ConnectionEstablished += OnProcessorConnectCallback; + // and make sure we respond on closing + messageProcessor.ConnectionClosed += OnProcessorDisconnectCallback; + } + } + } + + /// + /// The synchronizer of sibling contacts. + /// + internal ContactManager Manager + { + get + { + return manager; + } + } + + /// + /// The handler that handles all incoming P2P framework messages. + /// + /// + /// The handler is defined at the name server niveau which implies there is a single + /// p2p handler instance for every logged in account. All switchboard sessions route their messages + /// to this p2p handler. This enables the feature to start a p2p session in one switchboard session, + /// and continue, or close it, in another switchboard session. + /// + public P2PHandler P2PHandler + { + get + { + return p2pHandler; + } + internal protected set + { + p2pHandler = value; + } + } + + internal MSNTicket MSNTicket + { + get + { + return msnticket; + } + set + { + msnticket = value; + } + } + + /// + /// The scheduler identifier for + /// + internal Guid P2PInvitationSchedulerId + { + get + { + return p2pInviteSchedulerId; + } + } + + internal Guid SwitchBoardRequestSchedulerId + { + get + { + return sbRequestSchedulerId; + } + } + + #endregion + + #region Public Events + + /// + /// Occurs when an exception is thrown while handling the incoming or outgoing messages + /// + public event EventHandler ExceptionOccurred; + + /// + /// Occurs when the user could not be signed in due to authentication errors. Most likely due to an invalid account or password. Note that this event will also raise the more general event. + /// + public event EventHandler AuthenticationError; + + /// + /// Occurs when the user finished the authentication step, the owner was created + /// + public event EventHandler OwnerVerified; + + /// + /// Occurs when an answer is received after sending a ping to the MSN server via the SendPing() method + /// + public event EventHandler PingAnswer; + + /// + /// Occurs when any contact changes status. + /// + public event EventHandler ContactStatusChanged; + + /// + /// Occurs when any contact goes from offline status to another status. + /// + public event EventHandler ContactOnline; + + /// + /// Occurs when any contact goed from any status to offline status. + /// + public event EventHandler ContactOffline; + + /// + /// Occurs when any circle changes status. + /// + public event EventHandler CircleStatusChanged; + + /// + /// Occurs when any circle goes from offline status to another status. + /// + public event EventHandler CircleOnline; + + /// + /// Occurs when any circle goes from any status to offline status. + /// + public event EventHandler CircleOffline; + + /// + /// Occurs when any circle member goes from offline status to another status. + /// + public event EventHandler CircleMemberOnline; + + /// + /// Occurs when any circle member goes from any status to offline status. + /// + public event EventHandler CircleMemberOffline; + + /// + /// Occurs when any circle member changes status. + /// + public event EventHandler CircleMemberStatusChanged; + + /// + /// Occurs when a member left the circle conversation. + /// + public event EventHandler LeftCircleConversation; + + /// + /// Occurs when a member joined the circle conversation. + /// + public event EventHandler JoinedCircleConversation; + + /// + /// Occurs when the authentication and authorzation with the server has finished. The client is now connected to the messenger network. + /// + public event EventHandler SignedIn; + + /// + /// Occurs when the message processor has disconnected, and thus the user is no longer signed in. + /// + public event EventHandler SignedOff; + + /// + /// Occurs when a switchboard session has been created + /// + public event EventHandler SBCreated; + + /// + /// Occurs when the server notifies the client with the status of the owner's mailbox. + /// + public event EventHandler MailboxStatusReceived; + + /// + /// Occurs when new mail is received by the Owner. + /// + public event EventHandler NewMailReceived; + + /// + /// Occurs when unread mail is read or mail is moved by the Owner. + /// + public event EventHandler MailboxChanged; + + /// + /// Occurs when the server sends an error. + /// + public event EventHandler ServerErrorReceived; + + /// + /// Occurs when we receive a mobile message. + /// + public event EventHandler MobileMessageReceived; + + /// + /// Occurs when a circle member is typing. + /// + public event EventHandler CircleTypingMessageReceived; + + /// + /// Occurs when we receive a nudge message sent by a circle member. + /// + public event EventHandler CircleNudgeReceived; + + /// + /// Occurs when we receive a text message sent from a circle. + /// + public event EventHandler CircleTextMessageReceived; + + /// + /// Fire after received a message from other IM network (i.e. Yahoo! Messenger network)
+ /// This event is another source of incoming messages, since some IM can communicate + /// with MSN. MSN will deliver messages from these network to MSN client by NS server. + ///
+ public event EventHandler CrossNetworkMessageReceived; + + #endregion + + #region Public Methods + + #region Mobile + + /// + /// Sets the telephonenumber for the contact list owner's homephone. + /// + internal void SetPhoneNumberHome(string number) + { + if (ContactList.Owner == null) + throw new MSNPSharpException("Not a valid owner"); + + if (number.Length > 30) + throw new MSNPSharpException("Telephone number too long. Maximum length for a phone number is 30 digits."); + + MessageProcessor.SendMessage(new NSMessage("PRP", new string[] { "PHH", HttpUtility.UrlEncode(number) })); + } + + /// + /// Sets the telephonenumber for the contact list owner's workphone. + /// + internal void SetPhoneNumberWork(string number) + { + if (ContactList.Owner == null) + throw new MSNPSharpException("Not a valid owner"); + + if (number.Length > 30) + throw new MSNPSharpException("Telephone number too long. Maximum length for a phone number is 30 digits."); + + MessageProcessor.SendMessage(new NSMessage("PRP", new string[] { "PHW", HttpUtility.UrlEncode(number) })); + } + + /// + /// Sets the telephonenumber for the contact list owner's mobile phone. + /// + internal void SetPhoneNumberMobile(string number) + { + if (ContactList.Owner == null) + throw new MSNPSharpException("Not a valid owner"); + + if (number.Length > 30) + throw new MSNPSharpException("Telephone number too long. Maximum length for a phone number is 30 digits."); + + MessageProcessor.SendMessage(new NSMessage("PRP", new string[] { "PHM", HttpUtility.UrlEncode(number) })); + } + + /// + /// Sets whether the contact list owner allows remote contacts to send messages to it's mobile device. + /// + internal void SetMobileAccess(bool enabled) + { + if (ContactList.Owner == null) + throw new MSNPSharpException("Not a valid owner"); + + MessageProcessor.SendMessage(new NSMessage("PRP", new string[] { "MOB", enabled ? "Y" : "N" })); + } + + /// + /// Sets whether the contact list owner has a mobile device enabled. + /// + internal void SetMobileDevice(bool enabled) + { + if (ContactList.Owner == null) + throw new MSNPSharpException("Not a valid owner"); + + MessageProcessor.SendMessage(new NSMessage("PRP", new string[] { "MBE", enabled ? "Y" : "N" })); + } + + /// + /// Sends a mobile message to the specified remote contact. This only works when the remote contact has it's mobile device enabled and has MSN-direct enabled. + /// + /// + /// + public virtual void SendMobileMessage(Contact receiver, string text) + { + SendMobileMessage(receiver, text, String.Empty, String.Empty); + } + + /// + /// Sends a mobile message to the specified remote contact. This only works when the remote contact has it's mobile device enabled and has MSN-direct enabled. + /// + /// + /// + /// + /// + public virtual void SendMobileMessage(Contact receiver, string text, string callbackNumber, string callbackDevice) + { + if (receiver.MobileAccess || receiver.ClientType == ClientType.PhoneMember) + { + string to = (receiver.ClientType == ClientType.PhoneMember) ? "tel:" + receiver.Mail : receiver.Mail; + + TextMessage txtMsg = new TextMessage(text); + MimeMessage mimeMessage = new MimeMessage(); + mimeMessage.InnerMessage = txtMsg; + mimeMessage.MimeHeader[MimeHeaderStrings.Content_Type] = "text/plain; charset=UTF-8"; + mimeMessage.MimeHeader["Dest-Agent"] = "mobile"; + + NSMessage nsMessage = new NSMessage("UUM", new string[] { to, ((int)receiver.ClientType).ToString(), ((int)NetworkMessageType.Text).ToString() }); + + nsMessage.InnerMessage = mimeMessage; + MessageProcessor.SendMessage(nsMessage); + + } + else + { + throw new MSNPSharpException("The specified contact has no mobile device enabled nor phone member."); + } + } + + + #endregion + + #region Send Message to other networks. + + /// + /// Send message to contacts in other IM networks. + /// + /// + /// + public void SendCrossNetworkMessage(Contact targetContact, TextMessage message) + { + if (targetContact.ClientType == ClientType.EmailMember) + { + SendMessageToYahooNetwork(targetContact, message, NetworkMessageType.Text); + } + else + { + throw new MSNPSharpException("Contact Network not supported."); + } + } + + /// + /// Send message to contacts in other IM networks. + /// + /// + /// + public void SendCrossNetworkMessage(Contact targetContact, NetworkMessageType type) + { + if (targetContact.ClientType == ClientType.EmailMember) + { + switch (type) + { + case NetworkMessageType.Nudge: + MimeMessage mimeMessage = new MimeMessage(false); + mimeMessage.MimeHeader["ID"] = "1"; + SendMessageToYahooNetwork(targetContact, mimeMessage, type); + break; + case NetworkMessageType.Typing: + //YIM typing message is different from MSN typing message. + //For MSN typing message, you need to pass a "\r\n" as content. + SendMessageToYahooNetwork(targetContact, null, type); + break; + } + } + else + { + throw new MSNPSharpException("Contact Network not supported."); + } + } + + private void SendMessageToYahooNetwork(Contact yimContact, NetworkMessage message, NetworkMessageType type) + { + string messageType = ((int)type).ToString(CultureInfo.InvariantCulture); + + MimeMessage mimeMessage = new MimeMessage(); + switch (type) + { + case NetworkMessageType.Nudge: + mimeMessage.MimeHeader[MimeHeaderStrings.Content_Type] = "text/x-msnmsgr-datacast"; + break; + case NetworkMessageType.Typing: + mimeMessage.MimeHeader[MimeHeaderStrings.Content_Type] = "text/x-msmsgscontrol"; + mimeMessage.MimeHeader[MimeHeaderStrings.TypingUser] = ContactList.Owner.Mail.ToLowerInvariant(); + break; + case NetworkMessageType.Text: + mimeMessage.MimeHeader[MimeHeaderStrings.Content_Type] = "text/plain; charset=UTF-8"; + mimeMessage.MimeHeader[MimeHeaderStrings.X_MMS_IM_Format] = (message as TextMessage).GetStyleString(); + break; + } + + NSMessage nsMessage = new NSMessage("UUM", new string[]{yimContact.Mail.ToLowerInvariant(), + ((int)ClientType.EmailMember).ToString(CultureInfo.InvariantCulture), + messageType}); + + mimeMessage.InnerMessage = message; + nsMessage.InnerMessage = mimeMessage; + + MessageProcessor.SendMessage(nsMessage); + + } + #endregion + + #region RequestSwitchboard & SendPing + + + /// + /// Sends a request to the server to start a new switchboard session. The specified switchboard handler will be associated with the new switchboard session. + /// + /// The switchboard handler to use. A switchboard processor will be created and connected to this handler. + /// The object that initiated the request for the switchboard. + /// + public virtual void RequestSwitchboard(SBMessageHandler switchboardHandler, object initiator) + { + pendingSwitchboards.Enqueue(new SwitchboardQueueItem(switchboardHandler, initiator)); + + Schedulers.SwitchBoardRequestScheduler.Enqueue(MessageProcessor, new NSMessage("XFR", new string[] { "SB" }), SwitchBoardRequestSchedulerId); + } + + + + /// + /// Sends PNG (ping) command. + /// + public virtual void SendPing() + { + if (Interlocked.CompareExchange(ref canSendPing, 0, 1) == 1) + { + MessageProcessor.SendMessage(new NSMessage("PNG")); + } + } + + #endregion + + #region RequestScreenName & SetScreenName & SetPersonalMessage + + /// + /// Send the server a request for the contact's screen name. + /// + /// + /// When the server replies with the screen name the Name property of the will + /// be updated. + /// + /// + internal void RequestScreenName(Contact contact) + { + if (contact.Guid == null || contact.Guid == Guid.Empty) + throw new InvalidOperationException("This is not a valid Messenger contact."); + + MessageProcessor.SendMessage(new NSMessage("SBP", new string[] { contact.Guid.ToString(), "MFN", MSNHttpUtility.NSEncode(contact.Name) })); + } + + /// + /// Sets the contactlist owner's screenname. After receiving confirmation from the server + /// this will set the Owner object's name which will in turn raise the NameChange event. + /// + internal void SetScreenName(string newName) + { + if (ContactList.Owner == null) + throw new MSNPSharpException("Not a valid owner"); + + if (string.IsNullOrEmpty(newName)) + newName = ContactList.Owner.Mail; + + if (ContactList.Owner.PassportVerified) + { + MessageProcessor.SendMessage(new NSMessage("PRP", new string[] { "MFN", MSNHttpUtility.NSEncode(newName) })); + } + + + StorageService.UpdateProfile(newName, ContactList.Owner.PersonalMessage != null && ContactList.Owner.PersonalMessage.Message != null ? ContactList.Owner.PersonalMessage.Message : String.Empty); + + } + + /// + /// Sets personal message. + /// + /// + internal void SetPersonalMessage(PersonalMessage pmsg) + { + if (ContactList.Owner == null) + throw new MSNPSharpException("Not a valid owner"); + + MessageProcessor.SendMessage(new NSPayLoadMessage("UUX", pmsg.Payload)); + + StorageService.UpdateProfile(ContactList.Owner.Name, pmsg.Message); + } + + internal void SetEndPointCapabilities() + { + if (ContactList.Owner == null) + throw new MSNPSharpException("Not a valid owner"); + + string xmlstr = "" + + ((long)ContactList.Owner.LocalEndPointClientCapacities).ToString() + ":" + ((long)ContactList.Owner.LocalEndPointClientCapacitiesEx).ToString() + + ""; + + MessageProcessor.SendMessage(new NSPayLoadMessage("UUX", xmlstr)); + } + + #endregion + + #region SetPrivacyMode & SetNotifyPrivacyMode & SetPresenceStatus + + /// + /// Set the contactlist owner's privacy mode. + /// + /// New privacy setting + internal void SetPrivacyMode(PrivacyMode privacy) + { + if (privacy == PrivacyMode.AllExceptBlocked) + MessageProcessor.SendMessage(new NSMessage("BLP", new string[] { "AL" })); + + if (privacy == PrivacyMode.NoneButAllowed) + MessageProcessor.SendMessage(new NSMessage("BLP", new string[] { "BL" })); + + } + + /// + /// Set the contactlist owner's notification mode on contact service. + /// + /// New notify privacy setting + internal void SetNotifyPrivacyMode(NotifyPrivacy privacy) + { + ContactList.Owner.SetNotifyPrivacy(privacy); + if (AutoSynchronize) + { + ContactService.UpdateMe(); + } + } + + /// + /// Set the status of the contact list owner (the client). + /// + /// 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. + /// + internal void SetPresenceStatus(PresenceStatus status) + { + // check whether we are allowed to send a CHG command + if (IsSignedIn == false) + throw new MSNPSharpException("Can't set status. You must wait for the SignedIn event before you can set an initial status."); + + string context = "0"; + bool isSetDefault = false; + + if (ContactList.Owner.DisplayImage != null && ContactList.Owner.DisplayImage.Image != null) + context = ContactList.Owner.DisplayImage.Context; + + if (status == PresenceStatus.Offline) + { + messageProcessor.Disconnect(); + } + else if (status != ContactList.Owner.Status) + { + string capacities = String.Empty; + + if (ContactList.Owner.LocalEndPointClientCapacities == ClientCapacities.None) + { + isSetDefault = true; + + //don't set the same status or it will result in disconnection + ContactList.Owner.LocalEndPointClientCapacities = ClientCapacities.Default; + + if (BotMode) + { + ContactList.Owner.LocalEndPointClientCapacities |= ClientCapacities.IsBot; + } + + ContactList.Owner.LocalEndPointClientCapacitiesEx = ClientCapacitiesEx.Default; + + SetEndPointCapabilities(); + SetPresenceStatusUUX(status); + + if (AutoSynchronize) + { + // Send BLP + SetPrivacyMode(ContactList.Owner.Privacy); + } + + SetPersonalMessage(ContactList.Owner.PersonalMessage); + + // Set screen name + SetScreenName(ContactList.Owner.Name); + } + + ClientCapacitiesEx capsext = ContactList.Owner.LocalEndPointClientCapacitiesEx; + capacities = ((long)ContactList.Owner.LocalEndPointClientCapacities).ToString() + ":" + ((long)capsext).ToString(); + + if (!isSetDefault) + { + //Well, only update the status after receiving the CHG command is right. However, + //we need to send UUX before CHG. + + SetPresenceStatusUUX(status); + } + + MessageProcessor.SendMessage(new NSMessage("CHG", new string[] { ParseStatus(status), capacities, context })); + } + } + + internal void SetPresenceStatusUUX(PresenceStatus status) + { + if (ContactList.Owner == null) + throw new MSNPSharpException("Not a valid owner"); + + MessageProcessor.SendMessage(new NSPayLoadMessage("UUX", + "" + + "" + MSNHttpUtility.XmlEncode(ContactList.Owner.EpName) + "" + + "" + ((status == PresenceStatus.Idle) ? "true" : "false") + "" + + "1" + + "" + ParseStatus(status) + "" + + "") + ); + } + + internal void BroadCastStatus() + { + // check whether we are allowed to send a CHG command + if (IsSignedIn == false) + throw new MSNPSharpException("Can't set status. You must wait for the SignedIn event before you can set an initial status."); + + string context = String.Empty; + + if (ContactList.Owner.DisplayImage != null) + context = ContactList.Owner.DisplayImage.Context; + + ClientCapacitiesEx capsext = ContactList.Owner.LocalEndPointClientCapacitiesEx; + string capacities = ((long)ContactList.Owner.LocalEndPointClientCapacities).ToString() + ":" + ((long)capsext).ToString(); + + MessageProcessor.SendMessage(new NSMessage("CHG", new string[] { ParseStatus(ContactList.Owner.Status), capacities, context })); + } + + + #endregion + + #region Circle + + internal void SendBlockCircleNSCommands(Guid circleId, string hostDomain) + { + SendCircleNotifyRML(circleId, hostDomain, MSNLists.AllowedList, true); + SendCircleNotifyADL(circleId, hostDomain, MSNLists.BlockedList, true); + } + + internal void SendUnBlockCircleNSCommands(Guid circleId, string hostDomain) + { + SendCircleNotifyRML(circleId, hostDomain, MSNLists.BlockedList, true); + SendCircleNotifyADL(circleId, hostDomain, MSNLists.AllowedList, true); + } + + /// + /// Send a PUT command notifying the server we join to a circle(gruop) conversation. + /// + /// + /// + internal void JoinCircleConversation(Guid circleId, string hostDomain) + { + //Send PUT + string from = ((int)ContactList.Owner.ClientType).ToString() + ":" + ContactList.Owner.Mail + ";epid=" + ContactList.Owner.MachineGuid.ToString("B").ToLowerInvariant(); + string to = ((int)ClientType.CircleMember).ToString() + ":" + circleId.ToString().ToLowerInvariant() + "@" + hostDomain; + + string routingInfo = CircleString.RoutingScheme.Replace(CircleString.ToReplacementTag, to); + routingInfo = routingInfo.Replace(CircleString.FromReplacementTag, from); + + string reliabilityInfo = CircleString.ReliabilityScheme.Replace(CircleString.StreamReplacementTag, "0"); + reliabilityInfo = reliabilityInfo.Replace(CircleString.SegmentReplacementTag, "0"); + + string messageInfo = CircleString.PUTCircleReplyMessageScheme; + string replyXML = CircleString.PUTPayloadXMLScheme.Replace(CircleString.OwnerReplacementTag, ContactList.Owner.Mail); + messageInfo = messageInfo.Replace(CircleString.ContentLengthReplacementTag, replyXML.Length.ToString()); + messageInfo = messageInfo.Replace(CircleString.XMLReplacementTag, replyXML); + + string putCommandString = CircleString.CircleMessageScheme; + putCommandString = putCommandString.Replace(CircleString.RoutingSchemeReplacementTag, routingInfo); + putCommandString = putCommandString.Replace(CircleString.ReliabilitySchemeReplacementTag, reliabilityInfo); + putCommandString = putCommandString.Replace(CircleString.MessageSchemeReplacementTag, messageInfo); + + NSPayLoadMessage nsMessage = new NSPayLoadMessage("PUT", putCommandString); + MessageProcessor.SendMessage(nsMessage); + } + + internal int SendCircleNotifyADL(Guid circleId, string hostDomain, MSNLists lists, bool blockUnBlock) + { + string payload = ""; + + NSPayLoadMessage nsMessage = new NSPayLoadMessage("ADL", payload); + MessageProcessor.SendMessage(nsMessage); + return nsMessage.TransactionID; + } + + internal int SendCircleNotifyRML(Guid circleId, string hostDomain, MSNLists lists, bool blockUnBlock) + { + string payload = ""; + + NSPayLoadMessage nsMessage = new NSPayLoadMessage("RML", payload); + MessageProcessor.SendMessage(nsMessage); + return nsMessage.TransactionID; + } + + internal void SendSHAAMessage(string circleTicket) + { + byte[] utf8ByteArray = Encoding.UTF8.GetBytes(circleTicket); + string nonce = Convert.ToBase64String(utf8ByteArray); + MessageProcessor.SendMessage(new NSMessage("USR", new string[] { "SHA", "A", nonce })); + } + + internal void SendSwitchBoardClosedNotify(string sessionId) + { + string host = GetSessionHost(sessionId); + if (string.IsNullOrEmpty(host)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "Session " + sessionId + " not found."); + return; + } + + if (ContactList.Owner.MPOPEnable && ContactList.Owner.HasSignedInWithMultipleEndPoints) + { + MessageProcessor.SendMessage(new NSPayLoadMessage("UUN", new string[] { ContactList.Owner.Mail, "5" }, sessionId + ";" + host)); + RemoveSession(sessionId); + } + } + + internal void SendSwitchBoardClosedNotify(string sessionId, string host) + { + if (ContactList.Owner.MPOPEnable && ContactList.Owner.HasSignedInWithMultipleEndPoints) + { + MessageProcessor.SendMessage(new NSPayLoadMessage("UUN", new string[] { ContactList.Owner.Mail, "5" }, sessionId + ";" + host)); + RemoveSession(sessionId); + } + } + + #endregion + + #endregion + + #region Command Handlers + + #region Login + + /// + /// Called when the message processor has disconnected. + /// + /// + /// + protected virtual void OnProcessorDisconnectCallback(object sender, EventArgs e) + { + OnSignedOff(new SignedOffEventArgs(SignedOffReason.None)); + } + + /// + /// Called when the message processor has established a connection. This function will + /// begin the login procedure by sending the VER command. + /// + /// + /// + protected virtual void OnProcessorConnectCallback(object sender, EventArgs e) + { + // Check for valid credentials + if (Credentials == null) + throw new MSNPSharpException("No Credentials passed in the NSMessageHandler"); + + SendInitialMessage(); + } + + /// + /// Send the first message to the server. + /// + protected virtual void SendInitialMessage() + { + // VER: MSN Protocol used + + (MessageProcessor as NSMessageProcessor).ResetTransactionID(); + + MessageProcessor.SendMessage(new NSMessage("VER", new string[] { "MSNP18", "CVR0" })); + } + + /// + /// Called when a VER command has been received. + /// + /// + /// Indicates that the server has approved our version of the protocol. This function will send the CVR command. + /// VER [Transaction] [Protocol1] ([Protocol2]) [Clientversion] + /// + /// + protected virtual void OnVERReceived(NSMessage message) + { + MsnProtocol msnProtocol = (MsnProtocol)Convert.ToInt32(message.CommandValues[0].ToString().Substring("MSNP".Length, 2)); + Credentials oldcred = Credentials; + Credentials = new Credentials(oldcred.Account, oldcred.Password, msnProtocol); + + // CVR: Send client information back + MessageProcessor.SendMessage(new NSMessage("CVR", + new string[] { + "0x040c", //The LCIDs in .net framework are different from Windows API: "0x" + CultureInfo.CurrentCulture.LCID.ToString("x4") + "winnt", + "5.1", + "i386", + Credentials.ClientInfo.MessengerClientName, + Credentials.ClientInfo.MessengerClientBuildVer, + Credentials.ClientInfo.MessengerClientBrand, + Credentials.Account + }) + ); + } + + /// + /// Called when a CVR command has been received. + /// + /// + /// Indicates that the server has approved our client details. This function will send the USR command. + /// CVR [Transaction] [Recommended version] [Recommended version] [Minimum version] [Download url] [Info url] + /// + /// + protected virtual void OnCVRReceived(NSMessage message) + { + // USR: Begin login procedure + MessageProcessor.SendMessage(new NSMessage("USR", new string[] { "SSO", "I", Credentials.Account })); + } + + /// + /// Called when a USR command has been received. + /// + /// + /// + /// USR [Transaction] [SSO|OK] [Account] [Policy|Verified] [Nonce] + /// + /// + protected virtual void OnUSRReceived(NSMessage message) + { + //single-sign-on stuff + if ((string)message.CommandValues[0] == "SSO") + { + string policy = (string)message.CommandValues[2]; + string nonce = (string)message.CommandValues[3]; + + try + { + SingleSignOnManager.Authenticate( + this, + policy, + delegate(object sender, EventArgs e) + { + if (messageProcessor != null && messageProcessor.Connected) + { + MBI mbi = new MBI(); + string response = + MSNTicket.SSOTickets[SSOTicketType.Clear].Ticket + " " + + mbi.Encrypt(MSNTicket.SSOTickets[SSOTicketType.Clear].BinarySecret, nonce); + + MessageProcessor.SendMessage(new NSMessage("USR", new string[] { "SSO", "S", response, MachineGuid.ToString("B") })); + } + }, + delegate(object sender, ExceptionEventArgs e) + { + if (messageProcessor != null) + messageProcessor.Disconnect(); + + OnAuthenticationErrorOccurred(e); + } + ); + } + catch (Exception exception) + { + if (messageProcessor != null) + messageProcessor.Disconnect(); + + OnAuthenticationErrorOccurred(new ExceptionEventArgs(exception)); + return; + } + } + else if ((string)message.CommandValues[0] == "OK") + { + // we sucesfully logged in + if (ContactList.Owner == null) + { + // set the owner's name and CID + ContactList.SetOwner(new Owner(WebServiceConstants.MessengerIndividualAddressBookId, message.CommandValues[1].ToString(), msnticket.OwnerCID, this)); + OnOwnerVerified(); + } + ContactList.Owner.PassportVerified = message.CommandValues[2].Equals("1"); + } + } + + /// + /// Fires the event. + /// + /// + protected internal virtual void OnSignedIn(EventArgs e) + { + isSignedIn = true; + p2pInviteSchedulerId = Schedulers.P2PInvitationScheduler.Register(messenger); + sbRequestSchedulerId = Schedulers.SwitchBoardRequestScheduler.Register(messenger); + + if (SignedIn != null) + SignedIn(this, e); + + SendPing(); //Ping the server for the first time. Then client programmer should handle the answer. + } + + /// + /// Fires the event. + /// + /// + protected virtual void OnSignedOff(SignedOffEventArgs e) + { + + if (messageProcessor != null && messageProcessor.Connected) + { + if (ContactList.Owner != null) + ContactList.Owner.SetStatus(PresenceStatus.Offline); + messageProcessor.Disconnect(); // The disconnect will trigger this again. + return; + } + + bool signedIn = Clear(); + + //This event had to be at the last, or error might happend if user call Connect + //in the SignedOff event. + // Do not trigger this event if the library is not signed in. + if (SignedOff != null && signedIn) + SignedOff(this, e); + } + + /// + /// Fires the event. + /// + /// + protected internal virtual void OnContactStatusChanged(ContactStatusChangedEventArgs e) + { + if (ContactStatusChanged != null) + ContactStatusChanged(this, e); + } + + /// + /// Fires the event. + /// + /// + protected internal virtual void OnContactOffline(ContactEventArgs e) + { + if (ContactOffline != null) + ContactOffline(this, e); + } + + /// + /// Fires the event. + /// + /// + protected virtual void OnContactOnline(ContactEventArgs e) + { + if (ContactOnline != null) + ContactOnline(this, e); + } + + #endregion + + #region Status + + + /// + /// Translates MSNStatus enumeration to messenger's textual status presentation. + /// + /// MSNStatus enum object representing the status to translate + /// The corresponding textual value + internal protected static string ParseStatus(PresenceStatus status) + { + switch (status) + { + case PresenceStatus.Online: + return "NLN"; + + case PresenceStatus.Busy: + case PresenceStatus.Phone: + return "BSY"; + + case PresenceStatus.Idle: + return "IDL"; + + case PresenceStatus.BRB: + case PresenceStatus.Away: + case PresenceStatus.Lunch: + return "AWY"; + + case PresenceStatus.Offline: + return "FLN"; + + case PresenceStatus.Hidden: + return "HDN"; + + default: + break; + } + + return "Unknown status"; + } + + /// + /// Translates messenger's textual status to the corresponding value of the Status enum. + /// + /// Textual MSN status received from server + /// The corresponding enum value + internal protected static PresenceStatus ParseStatus(string status) + { + switch (status) + { + case "NLN": + return PresenceStatus.Online; + + case "BSY": + case "PHN": + return PresenceStatus.Busy; + + case "IDL": + return PresenceStatus.Idle; + + case "BRB": + case "AWY": + case "LUN": + return PresenceStatus.Away; + + case "FLN": + return PresenceStatus.Offline; + + case "HDN": + return PresenceStatus.Hidden; + + default: + break; + } + + return PresenceStatus.Unknown; + } + + + /// + /// Called when a UBX command has been received. + /// UBX [type:account;via] [payload length] + /// + /// + protected virtual void OnUBXReceived(NSMessage message) + { + //check the payload length + if (message.InnerMessage == null) + return; + + string fullaccount = message.CommandValues[0].ToString(); // 1:username@hotmail.com;via=9:guid@live.com + + string account = string.Empty; + ClientType type = ClientType.PassportMember; + Circle circle = null; + Contact contact = null; + + if (fullaccount.Contains(CircleString.ViaCircleGroupSplitter)) + { + string[] usernameAndCircle = fullaccount.Split(';'); + type = (ClientType)int.Parse(usernameAndCircle[0].Split(':')[0]); + account = usernameAndCircle[0].Split(':')[1].ToLowerInvariant(); + + string circleMail = usernameAndCircle[1].Substring("via=9:".Length); + + circle = CircleList[circleMail]; + if (circle == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[OnUBXReceived] Cannot retrieve circle for user: " + fullaccount); + return; + } + else + { + if (!circle.HasMember(fullaccount, AccountParseOption.ParseAsFullCircleAccount)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[OnUBXReceived] Cannot retrieve user for from circle: " + fullaccount); + return; + } + + contact = circle.GetMember(fullaccount, AccountParseOption.ParseAsFullCircleAccount); + } + } + else + { + type = (ClientType)int.Parse(fullaccount.Split(':')[0]); + account = fullaccount.Split(':')[1].ToLowerInvariant(); + + if (account != ContactList.Owner.Mail.ToLowerInvariant()) + { + if (ContactList.HasContact(account, type)) + { + contact = ContactList.GetContact(account, type); + } + } + else + { + contact = ContactList.Owner; + } + } + + if (message.InnerBody != null && contact != null) + { + contact.SetPersonalMessage(new PersonalMessage(message)); + XmlDocument xmlDoc = new XmlDocument(); + try + { + xmlDoc.Load(new MemoryStream(message.InnerBody)); + + // Get Fridenly Name + string friendlyName = GetFriendlyNameFromUBXXmlData(xmlDoc); + contact.SetName(string.IsNullOrEmpty(friendlyName) ? contact.Mail : friendlyName); + + //Get UserTileLocation + contact.UserTileLocation = GetUserTileLocationFromUBXXmlData(xmlDoc); + + //Get endpoint data. + bool isPrivateEndPoint = (contact is Owner); + + #region Regular contacts + + if (!isPrivateEndPoint) + { + List endPoints = GetEndPointDataFromUBXXmlData(contact.Mail, xmlDoc, isPrivateEndPoint); + if (endPoints.Count > 0) + { + foreach (EndPointData epData in endPoints) + { + contact.EndPointData[epData.Id] = epData; + } + } + } + + #endregion + + #region Only for Owner, set private endpoint info. + + XmlNodeList privateEndPoints = xmlDoc.GetElementsByTagName("PrivateEndpointData"); //Only the owner will have this field. + + if (privateEndPoints.Count > 0) + { + PlaceChangedReason placechangeReason = (privateEndPoints.Count >= contact.EndPointData.Count ? PlaceChangedReason.SignedIn : PlaceChangedReason.SignedOut); + Dictionary epList = new Dictionary(0); + foreach (XmlNode pepdNode in privateEndPoints) + { + Guid id = new Guid(pepdNode.Attributes["id"].Value); + PrivateEndPointData privateEndPoint = (contact.EndPointData.ContainsKey(id) ? (contact.EndPointData[id] as PrivateEndPointData) : new PrivateEndPointData(contact.Mail, id)); + privateEndPoint.Name = (pepdNode["EpName"] == null) ? String.Empty : pepdNode["EpName"].InnerText; + privateEndPoint.Idle = (pepdNode["Idle"] == null) ? false : bool.Parse(pepdNode["Idle"].InnerText); + privateEndPoint.ClientType = (pepdNode["ClientType"] == null) ? "1" : pepdNode["ClientType"].InnerText; + privateEndPoint.State = (pepdNode["State"] == null) ? PresenceStatus.Unknown : ParseStatus(pepdNode["State"].InnerText); + epList[id] = privateEndPoint; + } + + + if (contact is Owner) + { + TriggerPlaceChangeEvent(epList); + + if (placechangeReason == PlaceChangedReason.SignedIn && + ContactList.Owner.MPOPMode == MPOP.AutoLogoff) + { + OwnersSignOut(); + } + } + } + + #endregion + } + catch (Exception xmlex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[OnUBXReceived] Xml parse error: " + xmlex.Message); + } + } + + } + + private void OwnersSignOut() + { + if (ContactList.Owner == null) + return; + Dictionary epDataClone = new Dictionary(ContactList.Owner.EndPointData); + if (ContactList.Owner.HasSignedInWithMultipleEndPoints) //The minimal count of EndPointData is 1. + { + if (ContactList.Owner.MPOPMode == MPOP.AutoLogoff) + { + ContactList.Owner.SignoutFrom(NSMessageHandler.MachineGuid); + } + } + } + + private void TriggerPlaceChangeEvent(Dictionary epList) + { + if (ContactList.Owner == null) + return; + + Dictionary epDataClone = new Dictionary(ContactList.Owner.EndPointData); + foreach (Guid id in epDataClone.Keys) + { + if (id == Guid.Empty) + continue; + + if (!epList.ContainsKey(id)) + { + if (id == NSMessageHandler.MachineGuid) + { + continue; + } + else + { + ContactList.Owner.SetChangedPlace(id, (epDataClone[id] as PrivateEndPointData).Name, PlaceChangedReason.SignedOut); + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "The account was signed out at another place: " + (epDataClone[id] as PrivateEndPointData).Name + " " + id, GetType().Name); + } + } + } + + foreach (Guid id in epList.Keys) + { + if (!epDataClone.ContainsKey(id)) + { + ContactList.Owner.SetChangedPlace(id, (epList[id] as PrivateEndPointData).Name, PlaceChangedReason.SignedIn); + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "The account was signed in at another place: " + (epList[id] as PrivateEndPointData).Name + " " + id, GetType().Name); + } + } + } + + private string GetFriendlyNameFromUBXXmlData(XmlDocument ubxData) + { + XmlNode friendlyNameNode = ubxData.SelectSingleNode(@"//Data/FriendlyName"); + if (friendlyNameNode != null) + { + return string.IsNullOrEmpty(friendlyNameNode.InnerXml) ? string.Empty : friendlyNameNode.InnerText; + } + + return string.Empty; + } + + private string GetUserTileLocationFromUBXXmlData(XmlDocument ubxData) + { + XmlNode userTileLocationNode = ubxData.SelectSingleNode(@"//Data/UserTileLocation"); + if (userTileLocationNode != null) + { + return string.IsNullOrEmpty(userTileLocationNode.InnerXml) ? string.Empty : userTileLocationNode.InnerText; + } + + return string.Empty; + } + + private List GetEndPointDataFromUBXXmlData(string endpointAccount, XmlDocument ubxData, bool isPrivateEndPoint) + { + List endPoints = new List(0); + + XmlNodeList endPointNodes = ubxData.GetElementsByTagName("EndpointData"); + if (endPointNodes.Count > 0) + { + foreach (XmlNode epNode in endPointNodes) + { + Guid epId = new Guid(epNode.Attributes["id"].Value); + string capsString = (epNode["Capabilities"] == null) ? "0:0" : epNode["Capabilities"].InnerText; + ClientCapacities clientCaps = ClientCapacities.None; + ClientCapacitiesEx clientCapsEx = ClientCapacitiesEx.None; + + string[] capsGroup = capsString.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); + if (capsGroup.Length > 0) + { + clientCaps = (ClientCapacities)uint.Parse(capsGroup[0]); + } + + if (capsGroup.Length > 1) + { + clientCapsEx = (ClientCapacitiesEx)uint.Parse(capsGroup[1]); + } + + EndPointData epData = (isPrivateEndPoint ? new PrivateEndPointData(endpointAccount, epId) : new EndPointData(endpointAccount, epId)); + epData.ClientCapacities = clientCaps; + epData.ClientCapacitiesEx = clientCapsEx; + endPoints.Add(epData); + } + } + + return endPoints; + } + + /// + /// Called when a NLN command has been received. + /// + /// + /// Indicates that a contact on the forward list went online. + /// NLN [status] [clienttype:account] [name] [clientcapacities:48] [displayimage] (MSNP18) + /// NLN [status] [account] [clienttype] [name] [clientcapacities:0] [displayimage] (MSNP16) + /// NLN [status] [account] [clienttype] [name] [clientcapacities] [displayimage] (MSNP15) + /// + /// + protected virtual void OnNLNReceived(NSMessage message) + { + PresenceStatus newstatus = ParseStatus(message.CommandValues[0].ToString()); + + ClientType type = ClientType.None; + string account = string.Empty; + string fullaccount = message.CommandValues[1].ToString(); // 1:username@hotmail.com;via=9:guid@live.com + Contact contact = null; + Circle circle = null; + ClientCapacities newcaps = ClientCapacities.None; + ClientCapacitiesEx newcapsex = ClientCapacitiesEx.None; + + string newName = (message.CommandValues.Count >= 3) ? message.CommandValues[2].ToString() : String.Empty; + string newDisplayImageContext = message.CommandValues.Count >= 5 ? message.CommandValues[4].ToString() : String.Empty; + + if (message.CommandValues.Count >= 4) + { + if (message.CommandValues[3].ToString().Contains(":")) + { + newcaps = (ClientCapacities)Convert.ToInt64(message.CommandValues[3].ToString().Split(':')[0]); + newcapsex = (ClientCapacitiesEx)Convert.ToInt64(message.CommandValues[3].ToString().Split(':')[1]); + } + else + { + newcaps = (ClientCapacities)Convert.ToInt64(message.CommandValues[3].ToString()); + } + + } + + if (fullaccount.Contains(CircleString.ViaCircleGroupSplitter)) + { + #region Circle Status, or Circle Member status + + string[] usernameAndCircle = fullaccount.Split(';'); + type = (ClientType)int.Parse(usernameAndCircle[0].Split(':')[0]); + account = usernameAndCircle[0].Split(':')[1].ToLowerInvariant(); + + string circleMail = usernameAndCircle[1].Substring("via=9:".Length); + circle = CircleList[circleMail]; + + string capabilityString = message.CommandValues[3].ToString(); + + if (capabilityString != "0:0") //This is NOT a circle's presence status. + { + if (circle == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "[OnNLNReceived] Cannot update status for user, circle not found: " + fullaccount); + return; + } + + if (!circle.HasMember(fullaccount, AccountParseOption.ParseAsFullCircleAccount)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "[OnNLNReceived] User not found in the specific circle: " + fullaccount + ", a contact was created by NSCommand."); + } + + contact = circle.ContactList.GetContact(account, type); + + contact.SetName(MSNHttpUtility.NSDecode(message.CommandValues[2].ToString())); + contact.EndPointData[Guid.Empty].ClientCapacities = newcaps; + contact.EndPointData[Guid.Empty].ClientCapacitiesEx = newcapsex; + + if (contact != ContactList.Owner && newDisplayImageContext.Length > 10) + { + if (contact.DisplayImage != newDisplayImageContext) + { + contact.UserTileLocation = newDisplayImageContext; + contact.FireDisplayImageContextChangedEvent(newDisplayImageContext); + } + } + + PresenceStatus oldStatus = contact.Status; + + if (oldStatus != newstatus) + { + contact.SetStatus(newstatus); + + // The contact changed status + OnCircleMemberStatusChanged(new CircleMemberStatusChanged(circle, contact, oldStatus)); + + // The contact goes online + OnCircleMemberOnline(new CircleMemberEventArgs(circle, contact)); + } + } + else + { + if (account == ContactList.Owner.Mail.ToLowerInvariant()) + { + if (circle == null) + return; + + PresenceStatus oldCircleStatus = circle.Status; + string[] guidDomain = circleMail.Split('@'); + + if (guidDomain.Length != 0 && (oldCircleStatus == PresenceStatus.Offline || oldCircleStatus == PresenceStatus.Hidden)) + { + //This is a PUT command send from server when we login. + JoinCircleConversation(new Guid(guidDomain[0]), guidDomain[1]); + } + + circle.SetStatus(newstatus); + + OnCircleStatusChanged(new CircleStatusChangedEventArgs(circle, oldCircleStatus)); + + OnCircleOnline(new CircleEventArgs(circle)); + + return; + } + } + + #endregion + } + else + { + type = (ClientType)int.Parse(fullaccount.Split(':')[0]); + account = fullaccount.Split(':')[1].ToLowerInvariant(); + contact = ContactList.GetContact(account, type); + + #region Contact Status + + if (contact != null) + { + + if (IsSignedIn && account == ContactList.Owner.Mail.ToLowerInvariant() && type == ClientType.PassportMember) + { + SetPresenceStatus(newstatus); + return; + } + + contact.SetName(MSNHttpUtility.NSDecode(newName)); + contact.EndPointData[Guid.Empty].ClientCapacities = newcaps; + contact.EndPointData[Guid.Empty].ClientCapacitiesEx = newcapsex; + + if (contact != ContactList.Owner && newDisplayImageContext.Length > 10) + { + if (contact.DisplayImage != newDisplayImageContext) + { + contact.UserTileLocation = newDisplayImageContext; + contact.FireDisplayImageContextChangedEvent(newDisplayImageContext); + } + } + + if (contact != ContactList.Owner) + { + if (message.CommandValues.Count >= 6 && type == ClientType.EmailMember) + { + newDisplayImageContext = message.CommandValues[5].ToString(); + contact.UserTileURL = new Uri(HttpUtility.UrlDecode(newDisplayImageContext)); + } + + PresenceStatus oldStatus = contact.Status; + contact.SetStatus(newstatus); + + // The contact changed status + OnContactStatusChanged(new ContactStatusChangedEventArgs(contact, oldStatus)); + + // The contact goes online + OnContactOnline(new ContactEventArgs(contact)); + } + } + #endregion + } + } + + /// + /// Called when a FLN command has been received. + /// + /// + /// Indicates that a user went offline. + /// FLN [clienttype:account] [caps:0] [networkpng] (MSNP18) + /// FLN [account] [clienttype] [caps:0] [networkpng] (MSNP16) + /// FLN [account] [clienttype] [caps] [networkpng] (MSNP15) + /// + /// + protected virtual void OnFLNReceived(NSMessage message) + { + ClientType type = ClientType.None; + string account = string.Empty; + string fullaccount = message.CommandValues[0].ToString(); // 1:username@hotmail.com;via=9:guid@live.com + Contact contact = null; + Circle circle = null; + ClientCapacities oldcaps = ClientCapacities.None; + ClientCapacitiesEx oldcapsex = ClientCapacitiesEx.None; + + if (message.CommandValues.Count >= 2) + { + if (message.CommandValues[1].ToString().Contains(":")) + { + oldcaps = (ClientCapacities)Convert.ToInt64(message.CommandValues[1].ToString().Split(':')[0]); + oldcapsex = (ClientCapacitiesEx)Convert.ToInt64(message.CommandValues[1].ToString().Split(':')[1]); + } + else + { + oldcaps = (ClientCapacities)Convert.ToInt64(message.CommandValues[1].ToString()); + } + } + + + if (fullaccount.Contains(CircleString.ViaCircleGroupSplitter)) + { + #region Circle and CircleMemberStatus + + string[] usernameAndCircle = fullaccount.Split(';'); + type = (ClientType)int.Parse(usernameAndCircle[0].Split(':')[0]); + account = usernameAndCircle[0].Split(':')[1].ToLowerInvariant(); + + string circleMail = usernameAndCircle[1].Substring("via=9:".Length); + circle = CircleList[circleMail]; + + if (circle == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "[OnFLNReceived] Cannot update status for user since circle not found: " + fullaccount); + return; + } + + if (account == ContactList.Owner.Mail.ToLowerInvariant()) //Circle status + { + string capabilityString = message.CommandValues[1].ToString(); + if (capabilityString == "0:0") //This is a circle's presence status. + { + + PresenceStatus oldCircleStatus = circle.Status; + circle.SetStatus(PresenceStatus.Offline); + + if (CircleStatusChanged != null) + CircleStatusChanged(this, new CircleStatusChangedEventArgs(circle, oldCircleStatus)); + + if (CircleOffline != null) + CircleOffline(this, new CircleEventArgs(circle)); + } + + return; + } + else + { + if (!circle.HasMember(fullaccount, AccountParseOption.ParseAsFullCircleAccount)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "[OnFLNReceived] Cannot update status for user since user not found in the specific circle: " + fullaccount); + return; + } + + contact = circle.ContactList.GetContact(account, type); + PresenceStatus oldStatus = contact.Status; + + if (oldStatus != PresenceStatus.Offline) + { + contact.SetStatus(PresenceStatus.Offline); + + // The contact changed status + OnCircleMemberStatusChanged(new CircleMemberStatusChanged(circle, contact, oldStatus)); + + // The contact goes online + OnCircleMemberOffline(new CircleMemberEventArgs(circle, contact)); + } + + return; + } + + #endregion + } + else + { + type = (ClientType)int.Parse(fullaccount.Split(':')[0]); + account = fullaccount.Split(':')[1].ToLowerInvariant(); + + contact = (account == ContactList.Owner.Mail.ToLowerInvariant() && type == ClientType.PassportMember) + ? ContactList.Owner : ContactList.GetContact(account, type); + + #region Contact Staus + + if (contact != null) + { + if (contact != ContactList.Owner && message.CommandValues.Count >= 3 && type == ClientType.EmailMember) + { + string newdp = message.CommandValues[2].ToString(); + contact.UserTileURL = new Uri(HttpUtility.UrlDecode(newdp)); + } + + PresenceStatus oldStatus = contact.Status; + contact.SetStatus(PresenceStatus.Offline); + + // the contact changed status + OnContactStatusChanged(new ContactStatusChangedEventArgs(contact, oldStatus)); + + // the contact goes offline + OnContactOffline(new ContactEventArgs(contact)); + } + + #endregion + } + } + + /// + /// Called when an OUT command has been received. + /// + /// + /// Indicates that the server has signed off the user. + /// OUT [Reason] + /// + /// + protected virtual void OnOUTReceived(NSMessage message) + { + if (message.CommandValues.Count == 1) + { + switch (message.CommandValues[0].ToString().ToUpper(System.Globalization.CultureInfo.InvariantCulture)) + { + case "OTH": + OnSignedOff(new SignedOffEventArgs(SignedOffReason.OtherClient)); + break; + case "SSD": + OnSignedOff(new SignedOffEventArgs(SignedOffReason.ServerDown)); + break; + default: + OnSignedOff(new SignedOffEventArgs(SignedOffReason.None)); + break; + } + } + else + OnSignedOff(new SignedOffEventArgs(SignedOffReason.None)); + } + + /// + /// Called when a UBN command has been received. + /// + /// + /// UBN [account;{GUID}] [1:xml data,2:sip invite, 3: MSNP2P SLP data, 4:logout, 10: TURN] [PayloadLegth] + /// + /// + protected virtual void OnUBNReceived(NSMessage message) + { + NetworkMessage networkMessage = message as NetworkMessage; + if (message.InnerBody != null) + { + switch (message.CommandValues[1].ToString()) + { + case "3": + case "10": + { + SLPMessage slpMessage = SLPMessage.Parse(message.InnerBody); + if (slpMessage.ContentType == "application/x-msnmsgr-transreqbody") + { + string account = message.CommandValues[0].ToString(); + if (account.Contains(";")) + account = account.Split(';')[0]; + + if (ContactList.HasContact(account, ClientType.PassportMember)) + { + Contact sender = ContactList.GetContact(account, ClientType.PassportMember); + if (sender.Status == PresenceStatus.Hidden || sender.Status == PresenceStatus.Offline) + { + //If not return, we will get a 217 error (User not online). + return; + } + } + SLPStatusMessage slpResponseMessage = new SLPStatusMessage(slpMessage.FromMail, 500, "Internal Error"); + slpResponseMessage.FromMail = slpMessage.ToMail; + slpResponseMessage.Via = slpMessage.Via; + slpResponseMessage.CSeq = slpMessage.CSeq; + slpResponseMessage.CallId = slpMessage.CallId; + slpResponseMessage.MaxForwards = slpMessage.MaxForwards; + slpResponseMessage.ContentType = @"application/x-msnmsgr-transrespbody"; + + slpResponseMessage.BodyValues["Listening"] = "false"; + slpResponseMessage.BodyValues["Conn-Type"] = "Firewall"; + slpResponseMessage.BodyValues["TCP-Conn-Type"] = "Firewall"; + slpResponseMessage.BodyValues["IPv6-global"] = string.Empty; + slpResponseMessage.BodyValues["UPnPNat"] = "false"; + slpResponseMessage.BodyValues["Capabilities-Flags"] = "1"; + slpResponseMessage.BodyValues["Nat-Trav-Msg-Type"] = "WLX-Nat-Trav-Msg-Direct-Connect-Resp"; + slpResponseMessage.BodyValues["Bridge"] = "TCPv1"; + + if (slpMessage.BodyValues.ContainsKey("Hashed-Nonce")) + { + slpResponseMessage.BodyValues["Hashed-Nonce"] = slpMessage.BodyValues["Hashed-Nonce"].Value; + } + else + { + slpResponseMessage.BodyValues["Hashed-Nonce"] = Guid.Empty.ToString("B"); + } + + NSPayLoadMessage uunResponse = new NSPayLoadMessage("UUN", new string[] { message.CommandValues[0].ToString(), "3" }, + System.Text.Encoding.UTF8.GetString(slpResponseMessage.GetBytes(false))); + + MessageProcessor.SendMessage(uunResponse); + } + else if (slpMessage.ContentType == "application/x-msnmsgr-transrespbody") + { + SLPRequestMessage slpResponseMessage = new SLPRequestMessage(slpMessage.FromMail, MSNSLPRequestMethod.ACK); + slpResponseMessage.FromMail = slpMessage.ToMail; + slpResponseMessage.Via = slpMessage.Via; + slpResponseMessage.CSeq = 0; + slpResponseMessage.CallId = Guid.Empty; + slpResponseMessage.MaxForwards = 0; + slpResponseMessage.ContentType = @"application/x-msnmsgr-transdestaddrupdate"; + + slpResponseMessage.BodyValues["stroPdnAsrddAlanretnI4vPI"] = "0435:001.2.861.291"; + slpResponseMessage.BodyValues["Nat-Trav-Msg-Type"] = "WLX-Nat-Trav-Msg-Updated-Connecting-Port"; + + NSPayLoadMessage uunResponse = new NSPayLoadMessage("UUN", new string[] { message.CommandValues[0].ToString(), "3" }, + System.Text.Encoding.UTF8.GetString(slpResponseMessage.GetBytes(false))); + + MessageProcessor.SendMessage(uunResponse); + } + else if (slpMessage.ContentType == "application/x-msnmsgr-turnsetup") + { + SLPRequestMessage request = slpMessage as SLPRequestMessage; + if (request != null && request.Method == "ACK") + { + HttpWebRequest wr = (HttpWebRequest)WebRequest.Create("https://" + request.BodyValues["ServerAddress"].Value); + wr.Proxy = ConnectivitySettings.WebProxy; + //wr.Credentials = new NetworkCredential(request.BodyValues["SessionUsername"].Value, request.BodyValues["SessionPassword"].Value); + + wr.Credentials = new NetworkCredential( + "INVALIDUSERNAME" + request.BodyValues["SessionUsername"].Value, + "INVALIDPASSWORD" + request.BodyValues["SessionPassword"].Value + ); + + wr.BeginGetResponse(delegate(IAsyncResult result) + { + try + { + using (Stream stream = ((WebRequest)result.AsyncState).EndGetResponse(result).GetResponseStream()) + { + using (StreamReader r = new StreamReader(stream, Encoding.UTF8)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "TURN response: " + r.ReadToEnd(), GetType().Name); + } + } + wr.Abort(); + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "TURN error: " + ex.ToString(), GetType().Name); + } + }, wr); + } + } + } + break; + + + case "4": + case "8": + { + string logoutMsg = Encoding.UTF8.GetString(message.InnerBody); + if (logoutMsg.StartsWith("goawyplzthxbye") || logoutMsg == "gtfo") + { + if (messageProcessor != null) + messageProcessor.Disconnect(); + } + return; + } + } + } + } + + + + + /// + /// Called when a UUN command has been received. + /// + /// + protected virtual void OnUUNReceived(NSMessage message) + { + } + + /// + /// Called when a UUX command has been received. + /// + /// + protected virtual void OnUUXReceived(NSMessage message) + { + } + + /// + /// Called when a CHG command has been received. + /// + /// + /// The notification server has confirmed our request for a status change. + /// This function sets the status of the contactlist owner. + /// CHG [Transaction] [Status] + /// + /// + protected virtual void OnCHGReceived(NSMessage message) + { + ContactList.Owner.SetStatus(ParseStatus((string)message.CommandValues[0])); + } + + #endregion + + #region Switchboard + + /// + /// Class used for items stored in the switchboard queue. + /// + protected class SwitchboardQueueItem + { + /// + /// The object that initiated the request. + /// + public object Initiator; + /// + /// The switchboard handler that will be handling the new switchboard session. + /// + public SBMessageHandler SwitchboardHandler; + + /// + /// Constructs a queue item. + /// + /// + /// + public SwitchboardQueueItem(SBMessageHandler switchboardHandler, object initiator) + { + Initiator = initiator; + SwitchboardHandler = switchboardHandler; + } + } + + internal void SetSession(string sessionId, string ip) + { + lock (sessions) + { + sessions[sessionId] = ip; + } + } + + private string GetSessionHost(string sessionId) + { + lock (sessions) + { + if (sessions.ContainsKey(sessionId)) + return sessions[sessionId]; + } + + return string.Empty; + } + + private bool RemoveSession(string sessionId) + { + lock (sessions) + return sessions.Remove(sessionId); + } + + /// + /// Fires the event. + /// + /// The switchboard created + /// The object that initiated the switchboard request. + /// + /// + /// Indecates that whether it is an anonymous request. + internal virtual void OnSBCreated(SBMessageHandler switchboard, object initiator, string account, string name, bool anonymous) + { + if (SBCreated != null) + SBCreated(this, new SBCreatedEventArgs(switchboard, initiator, account, name, anonymous)); + } + + /// + /// Called when a RNG command has been received. + /// + /// + /// Indicates that the user receives a switchboard session (chatsession) request. A connection to the switchboard will be established + /// and the corresponding events and objects are created. + /// RNG [Session] [IP:Port] 'CKI' [Hash] [Account] [Name] U messenger.msn.com 1 + /// + /// + protected virtual void OnRNGReceived(NSMessage message) + { + string account = string.Empty; + string name = string.Empty; + bool anonymous = false; + + if (message.CommandValues.Count >= 5) + { + account = message.CommandValues[4].ToString(); + } + + if (message.CommandValues.Count >= 6) + { + name = message.CommandValues[5].ToString(); + } + + Contact callingContact = ContactList.GetContact(account, ClientType.PassportMember); + if (callingContact.Lists == MSNLists.None) + { + anonymous = true; + } + + + // create a switchboard object + SBMessageHandler handler = new SBMessageHandler(this, callingContact, message.CommandValues[3].ToString(), message.CommandValues[0].ToString()); + SBMessageProcessor processor = handler.MessageProcessor as SBMessageProcessor; + + // set new connectivity settings + ConnectivitySettings newSettings = new ConnectivitySettings(processor.ConnectivitySettings); + string[] values = ((string)message.CommandValues[1]).Split(new char[] { ':' }); + + newSettings.Host = values[0]; + newSettings.Port = int.Parse(values[1], System.Globalization.CultureInfo.InvariantCulture); + processor.ConnectivitySettings = newSettings; + + // start connecting + processor.Connect(); + + // notify the client + OnSBCreated(handler, null, account, name, anonymous); + } + + /// + /// Called when a XFR command has been received. + /// + /// + /// Indicates that the notification server has send us the location of a switch-board server in order to + /// make contact with a client, or that we must switch to a new notification server. + /// XFR [Transaction] [SB|NS] [IP:Port] ['0'|'CKI'] [Hash|CurrentIP:CurrentPort] + /// + /// + protected virtual void OnXFRReceived(NSMessage message) + { + if ((string)message.CommandValues[0] == "NS") + { + // switch to a new notification server. That means reconnecting our current message processor. + SocketMessageProcessor processor = (SocketMessageProcessor)MessageProcessor; + + // disconnect first + processor.Disconnect(); + + // set new connectivity settings + ConnectivitySettings newSettings = new ConnectivitySettings(processor.ConnectivitySettings); + string[] values = ((string)message.CommandValues[1]).Split(new char[] { ':' }); + + newSettings.Host = values[0]; + newSettings.Port = int.Parse(values[1], System.Globalization.CultureInfo.InvariantCulture); + + processor.ConnectivitySettings = newSettings; + + // and reconnect. The login procedure will now start over again + processor.Connect(); + } + if ((string)message.CommandValues[0] == "SB") + { + if (pendingSwitchboards.Count > 0) + { + if (ContactList.Owner.Status == PresenceStatus.Offline) + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "Owner not yet online!", GetType().ToString()); + + SwitchboardQueueItem queueItem = (SwitchboardQueueItem)pendingSwitchboards.Dequeue(); + SBMessageProcessor processor = queueItem.SwitchboardHandler.MessageProcessor as SBMessageProcessor; + + // set new connectivity settings + ConnectivitySettings newSettings = new ConnectivitySettings(processor.ConnectivitySettings); + string[] values = ((string)message.CommandValues[1]).Split(new char[] { ':' }); + + newSettings.Host = values[0]; + newSettings.Port = int.Parse(values[1], System.Globalization.CultureInfo.InvariantCulture); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Switchboard connectivity settings: " + newSettings.ToString(), GetType().Name); + + processor.ConnectivitySettings = newSettings; + + // set the switchboard objects with the processor values + string sessionHash = message.CommandValues[3].ToString(); + + queueItem.SwitchboardHandler.SetInvitation(sessionHash); + + + // notify the client + OnSBCreated(queueItem.SwitchboardHandler, queueItem.Initiator, string.Empty, string.Empty, false); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "SB created event handler called", GetType().Name); + + // start connecting + processor.Connect(); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Opening switchboard connection...", GetType().Name); + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "Switchboard request received, but no pending switchboards available.", GetType().Name); + } + } + } + + protected virtual void OnSBSReceived(NSMessage message) + { + } + + /// + /// Called when a UBM command has been received, this message was sent by a Yahoo Messenger client. + /// + /// + /// Indicates that the notification server has send us a UBM. This is usually a message from Yahoo Messenger. + /// UBM [Remote user account] [Remote user client type] [Destination user account] [Destination user client type] [3(nudge) or 2(typing) or 1(text message)] [Length] + /// + /// + protected virtual void OnUBMReceived(NSMessage message) + { + string sender = message.CommandValues[0].ToString(); + int senderType = 0; + int.TryParse(message.CommandValues[1].ToString(), out senderType); + + string receiver = message.CommandValues[2].ToString(); + int receiverType = 0; + int.TryParse(message.CommandValues[3].ToString(), out receiverType); + + int messageType = 0; + int.TryParse(message.CommandValues[4].ToString(), out messageType); + NetworkMessageType networkMessageType = (NetworkMessageType)messageType; + + if (!(receiverType == (int)ContactList.Owner.ClientType && + receiver.ToLowerInvariant() == ContactList.Owner.Mail.ToLowerInvariant())) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "[OnUBMReceived] The receiver is not owner, receiver account = " + receiver + + ", receiver type = " + (ClientType)receiverType); + + return; + } + + if (!ContactList.HasContact(sender, (ClientType)senderType)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "[OnUBMReceived] The sender is not in contact list, sender account = " + sender + + ", sender type = " + (ClientType)senderType); + + return; + } + + Contact from = ContactList.GetContact(sender, (ClientType)senderType); + Contact to = ContactList.Owner; + + MimeMessage mimeMessage = message.InnerMessage as MimeMessage; + + + #region Mobile Message + + if (senderType == (int)ClientType.PhoneMember) + { + switch (networkMessageType) + { + case NetworkMessageType.Text: + OnMobileMessageReceived(new CrossNetworkMessageEventArgs(from, to, messageType, mimeMessage.InnerMessage as TextMessage)); + break; + } + return; + } + + #endregion + + if (mimeMessage.MimeHeader.ContainsKey(MimeHeaderStrings.Content_Type)) + { + + switch (mimeMessage.MimeHeader[MimeHeaderStrings.Content_Type]) + { + case "text/x-msmsgscontrol": + { + OnCrossNetworkMessageReceived( + new CrossNetworkMessageEventArgs(from, to, (int)NetworkMessageType.Typing, mimeMessage.InnerMessage as TextPayloadMessage)); + break; + } + case "text/x-msnmsgr-datacast": + { + + if (mimeMessage.InnerMessage is MimeMessage) + { + MimeMessage innerMime = mimeMessage.InnerMessage as MimeMessage; + + if (innerMime.MimeHeader.ContainsKey("ID")) + { + if (innerMime.MimeHeader["ID"] == "1") + { + OnCrossNetworkMessageReceived( + new CrossNetworkMessageEventArgs(from, to, (int)NetworkMessageType.Nudge, innerMime)); + } + } + } + break; + } + + } + + if (mimeMessage.MimeHeader[MimeHeaderStrings.Content_Type].ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf("text/plain") >= 0) + { + OnCrossNetworkMessageReceived(new CrossNetworkMessageEventArgs(from, to, (int)NetworkMessageType.Text, mimeMessage.InnerMessage as TextMessage)); + } + } + + + } + + protected virtual void OnCrossNetworkMessageReceived(CrossNetworkMessageEventArgs e) + { + if (CrossNetworkMessageReceived != null) + CrossNetworkMessageReceived(this, e); + } + + #endregion + + #region Mail and Notification + + /// + /// Called when a NOT command has been received. + /// + /// + /// Indicates that a notification message has been received. + /// NOT [body length] + /// + /// + protected virtual void OnNOTReceived(NSMessage message) + { + // build a notification message + NotificationMessage notification = new NotificationMessage(message); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Notification received : " + notification.BodyPayload); + + if (AutoSynchronize == false || BotMode) + return; + + if (notification.NotificationTypeSpecified == false && + notification.Id == 0 && + notification.SiteId == 45705 && + notification.MessageId == 0 && + notification.SendDevice == "messenger" && + notification.ReceiverAccount.ToLowerInvariant() == ContactList.Owner.Mail.ToLowerInvariant()) + { + string xmlString = notification.BodyPayload; + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.LoadXml(xmlString); + + XmlNode node = xmlDoc.SelectSingleNode(@"//NotificationData"); + + if (node == null) + return; + + node = xmlDoc.SelectSingleNode(@"//NotificationData/Service"); + if (node != null) + { + if (node.InnerText != "ABCHInternal") + return; + + node = xmlDoc.SelectSingleNode(@"//NotificationData/CID"); + if (node == null) + return; + if (node.InnerText != ContactList.Owner.CID.ToString()) + return; + + ContactService.ServerNotificationRequest(PartnerScenario.ABChangeNotifyAlert, null, null); + } + else + { + node = xmlDoc.SelectSingleNode(@"//NotificationData/CircleId"); + if (node == null) + return; + + string abId = node.InnerText; + node = xmlDoc.SelectSingleNode(@"//NotificationData/Role"); + + CirclePersonalMembershipRole role = CirclePersonalMembershipRole.Member; + if (node != null) + { + role = (CirclePersonalMembershipRole)Enum.Parse(typeof(CirclePersonalMembershipRole), node.InnerText); + } + + object[] param = new object[] { abId, role }; + ContactService.ServerNotificationRequest(PartnerScenario.CircleIdAlert, param, null); + } + } + } + + /// + /// Called when a MSG command has been received. + /// + /// + /// Indicates that the notification server has send us a MSG. + /// This is usually a MSG from the 'HOTMAIL' user (account is also 'HOTMAIL') which includes notifications + /// about the contact list owner's profile, new mail, number of unread mails in the inbox, offline messages, etc. + /// MSG [Account] [Name] [Length] + /// + /// + protected virtual void OnMSGReceived(NSMessage message) + { + MimeMessage mimeMessage = message.InnerMessage as MimeMessage; + string mime = mimeMessage.MimeHeader[MimeHeaderStrings.Content_Type].ToString(); + + if (mime.IndexOf("text/x-msmsgsprofile") >= 0) + { + StrDictionary hdr = mimeMessage.MimeHeader; + + int clientPort = 0; + + if (hdr.ContainsKey("ClientPort")) + { + clientPort = int.Parse(mimeMessage.MimeHeader["ClientPort"].Replace('.', ' '), System.Globalization.CultureInfo.InvariantCulture); + clientPort = ((clientPort & 255) * 256) + ((clientPort & 65280) / 256); + } + + IPAddress ip = hdr.ContainsKey("ClientIP") ? IPAddress.Parse(hdr["ClientIP"]) : IPAddress.None; + ContactList.Owner.UpdateProfile( + hdr["LoginTime"], + (hdr.ContainsKey("EmailEnabled")) ? (Convert.ToInt32(hdr["EmailEnabled"]) == 1) : false, + hdr["MemberIdHigh"], + hdr["MemberIdLow"], + hdr["lang_preference"], + hdr["preferredEmail"], + hdr["country"], + hdr["PostalCode"], + hdr["Gender"], + hdr["Kid"], + hdr["Age"], + hdr["Birthday"], + hdr["Wallet"], + hdr["sid"], + hdr["kv"], + hdr["MSPAuth"], + ip, + clientPort, + hdr.ContainsKey("Nickname") ? hdr["Nickname"] : String.Empty, + hdr.ContainsKey("MPOPEnabled") && hdr["MPOPEnabled"] != "0", + hdr.ContainsKey("RouteInfo") ? hdr["RouteInfo"] : String.Empty + ); + + if (IPAddress.None != ip) + { + // set the external end point. This can be used in file transfer connectivity determing + externalEndPoint = new IPEndPoint(ip, clientPort); + } + + try + { + ContactService.SynchronizeContactList(); + } + catch (Exception ex) + { + OnExceptionOccurred(new ExceptionEventArgs(new MSNPSharpException("SynchronizeContactList Error.", ex))); + } + } + else if (mime.IndexOf("x-msmsgsemailnotification") >= 0) + { + MimeMessage mimeEmailNotificationMessage = mimeMessage.InnerMessage as MimeMessage; + + OnMailNotificationReceived(new NewMailEventArgs( + mimeMessage.MimeHeader[MimeHeaderStrings.From], + mimeEmailNotificationMessage.MimeHeader["Message-URL"], + mimeEmailNotificationMessage.MimeHeader["Post-URL"], + mimeEmailNotificationMessage.MimeHeader["Subject"], + mimeEmailNotificationMessage.MimeHeader["Dest-Folder"], + mimeEmailNotificationMessage.MimeHeader["From-Addr"], + mimeEmailNotificationMessage.MimeHeader.ContainsKey("id") ? int.Parse(mimeEmailNotificationMessage.MimeHeader["id"], System.Globalization.CultureInfo.InvariantCulture) : 0 + )); + } + else if (mime.IndexOf("x-msmsgsactivemailnotification") >= 0) + { + //Now this is the unread OIM info, not the new mail. + MimeMessage mimeActiveEmailNotificationMessage = mimeMessage.InnerMessage as MimeMessage; + + OnMailChanged(new MailChangedEventArgs( + mimeActiveEmailNotificationMessage.MimeHeader["Src-Folder"], + mimeActiveEmailNotificationMessage.MimeHeader["Dest-Folder"], + mimeActiveEmailNotificationMessage.MimeHeader.ContainsKey("Message-Delta") ? int.Parse(mimeActiveEmailNotificationMessage.MimeHeader["Message-Delta"], System.Globalization.CultureInfo.InvariantCulture) : 0 + )); + } + else if (mime.IndexOf("x-msmsgsinitialemailnotification") >= 0) + { + MimeMessage mimeInitialEmailNotificationMessage = mimeMessage.InnerMessage as MimeMessage; + + OnMailboxStatusReceived(new MailboxStatusEventArgs( + mimeInitialEmailNotificationMessage.MimeHeader.ContainsKey("Inbox-Unread") ? int.Parse(mimeInitialEmailNotificationMessage.MimeHeader["Inbox-Unread"], System.Globalization.CultureInfo.InvariantCulture) : 0, + mimeInitialEmailNotificationMessage.MimeHeader.ContainsKey("Folders-Unread") ? int.Parse(mimeInitialEmailNotificationMessage.MimeHeader["Folders-Unread"], System.Globalization.CultureInfo.InvariantCulture) : 0, + mimeInitialEmailNotificationMessage.MimeHeader["Inbox-URL"], + mimeInitialEmailNotificationMessage.MimeHeader["Folders-URL"], + mimeInitialEmailNotificationMessage.MimeHeader["Post-URL"] + )); + } + else if (mime.IndexOf("x-msmsgsinitialmdatanotification") >= 0 || mime.IndexOf("x-msmsgsoimnotification") >= 0) + { + MimeMessage innerMimeMessage = mimeMessage.InnerMessage as MimeMessage; + + + /* + * + * + * 884 Inbox total + * 0 Inbox unread mail + * 222 Sent + Junk + Drafts + * 15 Junk unread mail + * + * + * 409600 + * 204800 + * + * + * + * + * + * + * + * + */ + + string xmlstr = innerMimeMessage.MimeHeader["Mail-Data"]; + try + { + XmlDocument xdoc = new XmlDocument(); + xdoc.LoadXml(xmlstr); + XmlNodeList mdnodelist = xdoc.GetElementsByTagName("MD"); + if (mdnodelist.Count > 0) + { + foreach (XmlNode node in mdnodelist[0]) + { + if (node.Name.ToLowerInvariant() == "e" && node.HasChildNodes) + { + int iu = 0; + int ou = 0; + foreach (XmlNode cnode in node.ChildNodes) + { + if (cnode.Name.ToLowerInvariant() == "iu") + { + int.TryParse(cnode.InnerText, out iu); + break; + } + } + + foreach (XmlNode cnode in node.ChildNodes) + { + if (cnode.Name.ToLowerInvariant() == "ou") + { + int.TryParse(cnode.InnerText, out ou); + break; + } + } + + OnMailboxStatusReceived(new MailboxStatusEventArgs( + iu, + ou, + innerMimeMessage.MimeHeader["Inbox-URL"], + innerMimeMessage.MimeHeader["Folders-URL"], + innerMimeMessage.MimeHeader["Post-URL"] + )); + break; + } + } + } + + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, ex.Message, GetType().Name); + } + + OIMService.ProcessOIM(innerMimeMessage, mime.IndexOf("x-msmsgsinitialmdatanotification") >= 0); + } + } + + /// + /// Fires the event. + /// + /// Called when the owner has removed or moved e-mail. + /// + protected virtual void OnMailChanged(MailChangedEventArgs e) + { + if (MailboxChanged != null) + { + MailboxChanged(this, e); + } + } + + /// + /// Fires the event. + /// + /// Called when the server sends the status of the owner's mailbox. + /// + protected virtual void OnMailboxStatusReceived(MailboxStatusEventArgs e) + { + if (MailboxStatusReceived != null) + { + MailboxStatusReceived(this, e); + } + } + + /// + /// Fires the event. + /// + /// Called when the owner has received new e-mail, or e-mail has been removed / moved. + /// + protected virtual void OnMailNotificationReceived(NewMailEventArgs e) + { + if (NewMailReceived != null) + { + NewMailReceived(this, e); + } + } + + /// + /// Fires the event. + /// + /// Called when the owner has received a mobile message. + /// + protected virtual void OnMobileMessageReceived(CrossNetworkMessageEventArgs e) + { + if (MobileMessageReceived != null) + { + MobileMessageReceived(this, e); + } + } + + #endregion + + #region Contact, Circle and Group + + /// + /// Translates the codes used by the MSN server to a MSNList object. + /// + /// + /// + protected virtual MSNLists GetMSNList(string name) + { + switch (name) + { + case "AL": + return MSNLists.AllowedList; + case "FL": + return MSNLists.ForwardList; + case "BL": + return MSNLists.BlockedList; + case "RL": + return MSNLists.ReverseList; + case "PL": + return MSNLists.PendingList; + } + throw new MSNPSharpException("Unknown MSNList type"); + } + + /// + /// Called when a ADL command has been received. + /// ADL [TransactionID] [OK] + /// + /// + protected virtual void OnADLReceived(NSMessage message) + { + if (message.TransactionID != 0 && + message.CommandValues[0].ToString() == "OK" && + ContactService.ProcessADL(message.TransactionID)) + { + } + else + { + NetworkMessage networkMessage = message as NetworkMessage; + if (networkMessage.InnerBody != null) //Payload ADL command + { + #region NORMAL USER + if (AutoSynchronize) + { + ContactService.msRequest( + PartnerScenario.MessengerPendingList, + null /****************************************** + * + * ALL CHANGES WILL BE MADE BY msRequest() + * + ****************************************** + delegate + { + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.Load(new MemoryStream(networkMessage.InnerBody)); + XmlNodeList domains = xmlDoc.GetElementsByTagName("d"); + string domain = String.Empty; + foreach (XmlNode domainNode in domains) + { + domain = domainNode.Attributes["n"].Value; + XmlNode contactNode = domainNode.FirstChild; + do + { + string account = contactNode.Attributes["n"].Value + "@" + domain; + ClientType type = (ClientType)int.Parse(contactNode.Attributes["t"].Value); + MSNLists list = (MSNLists)int.Parse(contactNode.Attributes["l"].Value); + string displayName = account; + try + { + displayName = contactNode.Attributes["f"].Value; + } + catch (Exception) + { + } + + if (ContactList.HasContact(account, type)) + { + Contact contact = ContactList.GetContact(account, type); + + // Fire ReverseAdded. If this contact on Pending list other person added us, otherwise we added and other person accepted. + if (contact.OnPendingList || contact.OnReverseList) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "ADL received, ReverseAdded event fired. Contact is in list: " + contact.Lists.ToString()); + ContactService.OnReverseAdded(new ContactEventArgs(contact)); + } + } + else + { + if (list == MSNLists.ReverseList) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "ADL received, ReverseAdded will fire shortly. Please WAIT addressbook change event...", GetType().Name); + } + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, account + ":" + type + " was added to your " + list.ToString(), GetType().Name); + + } while (contactNode.NextSibling != null); + } + + }*****/ + ); + } + #endregion + #region BOT MODE + else + { + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.Load(new MemoryStream(networkMessage.InnerBody)); + XmlNodeList domains = xmlDoc.GetElementsByTagName("d"); + string domain = String.Empty; + foreach (XmlNode domainNode in domains) + { + domain = domainNode.Attributes["n"].Value; + XmlNode contactNode = domainNode.FirstChild; + do + { + string account = contactNode.Attributes["n"].Value + "@" + domain; + ClientType type = (ClientType)int.Parse(contactNode.Attributes["t"].Value); + MSNLists list = (MSNLists)int.Parse(contactNode.Attributes["l"].Value); + string displayName = account; + try + { + displayName = contactNode.Attributes["f"].Value; + } + catch (Exception) + { + } + + if (list == MSNLists.ReverseList) + { + Contact contact = ContactList.GetContact(account, displayName, type); + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "[BOTMODE] ADL received, ReverseAdded event fired. Contact is in list: " + contact.Lists.ToString()); + contact.Lists |= MSNLists.ReverseList; + ContactService.OnReverseAdded(new ContactEventArgs(contact)); + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, account + ":" + type + " was added to your " + list.ToString(), GetType().Name); + + } while (contactNode.NextSibling != null); + } + } + #endregion + } + } + } + + /// + /// Called when a RML command has been received. + /// + /// Indicates that someone was removed from a list by local user (RML [Trans-ID] OK) + /// or local user was removed from someone's reverse list (RML 0 [Trans-ID]\r\n[payload]). + /// + protected virtual void OnRMLReceived(NSMessage nsMessage) + { + NetworkMessage networkMessage = nsMessage as NetworkMessage; + if (networkMessage.InnerBody != null) //Payload RML command. + { + if (AutoSynchronize) + { + ContactService.msRequest(PartnerScenario.Initial, null); + } + + if (Settings.TraceSwitch.TraceVerbose) + { + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.Load(new MemoryStream(networkMessage.InnerBody)); + XmlNodeList domains = xmlDoc.GetElementsByTagName("d"); + string domain = String.Empty; + foreach (XmlNode domainNode in domains) + { + domain = domainNode.Attributes["n"].Value; + XmlNode contactNode = domainNode.FirstChild; + do + { + string account = contactNode.Attributes["n"].Value + "@" + domain; + ClientType type = (ClientType)int.Parse(contactNode.Attributes["t"].Value); + MSNLists list = (MSNLists)int.Parse(contactNode.Attributes["l"].Value); + account = account.ToLower(CultureInfo.InvariantCulture); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, account + " has removed you from his/her " + list.ToString(), GetType().Name); + + } while (contactNode.NextSibling != null); + } + } + } + } + + /// + /// Called when an ADG command has been received. + /// + /// + /// Indicates that a contact group has been added to the contact group list. + /// Raises the ContactService.ContactGroupAdded event. + /// ADG [Transaction] [ListVersion] [Name] [GroupID] + /// + /// + protected virtual void OnADGReceived(NSMessage message) + { + if (AutoSynchronize) + { + ContactService.abRequest(PartnerScenario.ContactSave, null); + } + } + + /// + /// Called when a RMG command has been received. + /// + /// + /// Indicates that a contact group has been removed. + /// Raises the ContactService.ContactGroupRemoved event. + /// RMG [Transaction] [ListVersion] [GroupID] + /// + /// + protected virtual void OnRMGReceived(NSMessage message) + { + if (AutoSynchronize) + { + ContactService.abRequest(PartnerScenario.ContactSave, null); + } + } + + /// Called when a FQY (Federated Query) command has been received. + /// Indicates a client has different network types except PassportMember. + /// FQY [TransactionID] [PayloadLength] + /// + /// + /// + /// + protected virtual void OnFQYReceived(NSMessage message) + { + int pendingTransactionId = message.TransactionID; + if (ContactService.pendingFQYs.Contains(pendingTransactionId)) + { + lock (ContactService.pendingFQYs) + ContactService.pendingFQYs.Remove(pendingTransactionId); + + NetworkMessage networkMessage = message as NetworkMessage; + if (networkMessage.InnerBody != null) + { + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.Load(new MemoryStream(networkMessage.InnerBody)); + XmlNodeList domains = xmlDoc.GetElementsByTagName("d"); + string domain = String.Empty; + foreach (XmlNode domainNode in domains) + { + domain = domainNode.Attributes["n"].Value; + XmlNode contactNode = domainNode.FirstChild; + do + { + if (contactNode.Attributes["t"] != null && + contactNode.Attributes["t"].Value != null && + contactNode.Attributes["t"].Value != "0") + { + ClientType type = (ClientType)Enum.Parse(typeof(ClientType), contactNode.Attributes["t"].Value); + string account = (contactNode.Attributes["n"].Value + "@" + domain).ToLowerInvariant(); + String otherEmail = String.Empty; + if (contactNode.Attributes["actual"] != null) + { + // Save original (ex: yahoo.com.tr) as other email + otherEmail = String.Copy(account); + // Then use actual address, this is stript address (ex: yahoo.com) + account = contactNode.Attributes["actual"].Value.ToLowerInvariant(); + } + ContactService.AddNewContact(account, type, String.Empty, otherEmail); + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, String.Format("FQY: {0} has passport network only.", contactNode.Attributes["n"].Value + "@" + domain), GetType().Name); + } + + } while (contactNode.NextSibling != null); + } + } + } + } + + + /// + /// Called when a NFY command has been received. + /// Indicates that a circle operation occured. + /// + /// NFY [TransactionID] [Operation: PUT|DEL] [Payload Length]\r\n[Payload Data] + /// + /// + /// + protected virtual void OnNFYReceived(NSMessage message) + { + #region NFY PUT + + if (message.CommandValues[0].ToString() == "PUT") + { + NetworkMessage networkMessage = message as NetworkMessage; + if (networkMessage.InnerBody == null) + return; + + string nfyTextString = Encoding.UTF8.GetString(networkMessage.InnerBody); + int lastLineBreak = nfyTextString.LastIndexOf("\r\n"); + if (lastLineBreak == -1) + return; + + string xmlString = nfyTextString.Substring(lastLineBreak + 2); + string mimeString = nfyTextString.Substring(0, lastLineBreak).Replace("\r\n\r\n", "\r\n"); + byte[] mimeBytes = Encoding.UTF8.GetBytes(mimeString); + MimeDictionary mimeDic = new MimeDictionary(mimeBytes); + + if (!(mimeDic.ContainsKey(MimeHeaderStrings.Content_Type) && mimeDic.ContainsKey(MimeHeaderStrings.NotifType))) + return; + + if (mimeDic[MimeHeaderStrings.Content_Type].Value != "application/circles+xml") + return; + + string[] typeMail = mimeDic[MimeHeaderStrings.From].ToString().Split(':'); + + if (typeMail.Length == 0) + return; + + string[] guidDomain = typeMail[1].Split('@'); + if (guidDomain.Length == 0) + return; + + Circle circle = CircleList[typeMail[1]]; + + if (circle == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "[OnNFYReceived] Cannot complete the operation since circle not found: " + mimeDic[MimeHeaderStrings.From].ToString()); + return; + } + + if (xmlString == string.Empty) + return; //No xml content. + + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.LoadXml(xmlString); + + if (mimeDic[MimeHeaderStrings.NotifType].Value == "Full") + { + //This is an initial NFY + } + + XmlNodeList ids = xmlDoc.SelectNodes("//circle/roster/user/id"); + if (ids.Count == 0) + { + return; //I hate indent. + } + + foreach (XmlNode node in ids) + { + if (node.InnerText.Split(':').Length == 0) + return; + + string memberAccount = node.InnerText.Split(':')[1]; + if (memberAccount == ContactList.Owner.Mail.ToLowerInvariant()) + continue; + + ClientType memberType = (ClientType)int.Parse(node.InnerText.Split(':')[0]); + string id = node.InnerText + ";via=" + mimeDic[MimeHeaderStrings.From].ToString(); + + if (circle.HasMember(id, AccountParseOption.ParseAsFullCircleAccount)) + { + Contact contact = circle.ContactList.GetContact(memberAccount, memberType); + OnJoinedCircleConversation(new CircleMemberEventArgs(circle, contact)); + } + } + + } + + #endregion + + #region NFY DEL + if (message.CommandValues[0].ToString() == "DEL") + { + NetworkMessage networkMessage = message as NetworkMessage; + if (networkMessage.InnerBody == null) + { + return; + } + + string mimeString = Encoding.UTF8.GetString(networkMessage.InnerBody); + mimeString = mimeString.Replace("\r\n\r\n", "\r\n"); + byte[] mimeBytes = Encoding.UTF8.GetBytes(mimeString); + MimeDictionary mimeDic = new MimeDictionary(mimeBytes); + + if (!mimeDic.ContainsKey(MimeHeaderStrings.Uri)) + return; + string xpathUri = mimeDic[MimeHeaderStrings.Uri].ToString(); + if (xpathUri.IndexOf("/circle/roster(IM)/user") == -1) + return; + + string typeAccount = xpathUri.Substring("/circle/roster(IM)/user".Length); + typeAccount = typeAccount.Substring(typeAccount.IndexOf("(") + 1); + typeAccount = typeAccount.Substring(0, typeAccount.IndexOf(")")); + + if (!mimeDic.ContainsKey(MimeHeaderStrings.From)) + return; + + string circleID = mimeDic[MimeHeaderStrings.From].ToString(); + string[] typeCircleID = circleID.Split(':'); + if (typeCircleID.Length < 2) + return; + + if (CircleList[typeCircleID[1]] == null) + return; + + Circle circle = CircleList[typeCircleID[1]]; + + string fullAccount = typeAccount + ";via=" + circleID; + if (!circle.HasMember(fullAccount, AccountParseOption.ParseAsFullCircleAccount)) + return; + + Contact member = circle.GetMember(fullAccount, AccountParseOption.ParseAsFullCircleAccount); + OnLeftCircleConversation(new CircleMemberEventArgs(circle, member)); + + + + } + + #endregion + } + + /// + /// Called when a SDG command has been received. + /// Indicates that someone send us a message from a circle group. + /// + /// SDG 0 [Payload Length]\r\n[Payload Data] + /// + /// + /// + protected virtual void OnSDGReceived(NSMessage message) + { + /*** typing message *** + SDG 0 421 + Routing: 1.0 + To: 9:00000000-0000-0000-0009-cdc0351b0c6d@live.com;path=IM + From: 1:updatedynamicitem@hotmail.com;epid={7a29dadd-503d-4c5c-8e6b-a599c15de981} + + Reliability: 1.0 + Stream: 0 + Segment: 1 + + Messaging: 1.0 + Content-Length: 2 + Content-Type: text/x-msmsgscontrol + Content-Transfer-Encoding: 7bit + Message-Type: Control + Message-Subtype: Typing + MIME-Version: 1.0 + TypingUser: updatedynamicitem@hotmail.com + ***/ + + /*** group text messaging *** + SDG 0 410 + Routing: 1.0 + To: 9:00000000-0000-0000-0009-cdc0351b0c6d@live.com;path=IM + From: 1:updatedynamicitem@hotmail.com;epid={7a29dadd-503d-4c5c-8e6b-a599c15de981} + + Reliability: 1.0 + Stream: 0 + Segment: 2 + + Messaging: 1.0 + Content-Length: 2 + Content-Type: Text/plain; charset=UTF-8 + Content-Transfer-Encoding: 7bit + Message-Type: Text + MIME-Version: 1.0 + X-MMS-IM-Format: FN=Segoe%20UI; EF=; CO=0; CS=1; PF=0 + + hi + ***/ + + NetworkMessage networkMessage = message as NetworkMessage; + if (networkMessage.InnerBody != null) + { + string payloadString = Encoding.UTF8.GetString(networkMessage.InnerBody); + int lastLineBreak = payloadString.LastIndexOf("\r\n"); + if (lastLineBreak != -1) + { + string contentString = payloadString.Substring(lastLineBreak + 2); + string mimeString = payloadString.Substring(0, lastLineBreak).Replace("\r\n\r\n", "\r\n"); + byte[] mimeBytes = Encoding.UTF8.GetBytes(mimeString); + MimeDictionary mimeDic = new MimeDictionary(mimeBytes); + + string[] typeMail = mimeDic[MimeHeaderStrings.To].Value.Split(':'); + if (typeMail.Length == 0) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[OnSDGReceived] Error: Cannot find circle type in id: " + mimeDic[MimeHeaderStrings.To].Value); + return; + } + + string[] guidDomain = typeMail[1].Split('@'); + if (guidDomain.Length == 0) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[OnSDGReceived] Error: Cannot find circle guid and host domain in id: " + typeMail[1]); + return; + } + + Circle circle = CircleList[typeMail[1]]; + if (circle == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[OnSDGReceived] Error: Cannot find circle " + typeMail[1] + " in your circle list."); + return; + } + + // 1:username@hotmail.com;via=9:guid@live.com + string fullAccount = mimeDic[MimeHeaderStrings.From].Value + ";via=" + mimeDic[MimeHeaderStrings.To].Value; + fullAccount = fullAccount.ToLowerInvariant(); + + Contact member = circle.GetMember(fullAccount, AccountParseOption.ParseAsFullCircleAccount); + + if (member == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[OnSDGReceived] Error: Cannot find circle type in id: " + mimeDic[MimeHeaderStrings.To].Value); + return; + } + + CircleMemberEventArgs arg = new CircleMemberEventArgs(circle, member); + + if (mimeDic.ContainsKey(MimeHeaderStrings.Content_Type) && mimeDic.ContainsKey(MimeHeaderStrings.Message_Subtype)) + { + if (mimeDic[MimeHeaderStrings.Content_Type].ToString().ToLowerInvariant() == "text/x-msmsgscontrol" && + mimeDic[MimeHeaderStrings.Message_Subtype].ToString().ToLowerInvariant() == "typing") + { + //Typing + OnCircleTypingMessageReceived(arg); + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "Circle: " + circle.ToString() + "\r\nMember: " + member.ToString() + "\r\nIs typing...."); + } + } + + if (mimeDic.ContainsKey(MimeHeaderStrings.Content_Type) && mimeDic.ContainsKey(MimeHeaderStrings.Message_Type)) + { + if (mimeDic[MimeHeaderStrings.Content_Type].ToString().ToLowerInvariant().IndexOf("text/plain;") > -1 && + mimeDic[MimeHeaderStrings.Message_Type].ToString().ToLowerInvariant() == "text") + { + //Text message. + TextMessage txtMessage = new TextMessage(contentString); + StrDictionary strDic = new StrDictionary(); + foreach (string key in mimeDic.Keys) + { + strDic.Add(key, mimeDic[key].ToString()); + } + + txtMessage.ParseHeader(strDic); + CircleTextMessageEventArgs textMessageArg = new CircleTextMessageEventArgs(txtMessage, circle, member); + OnCircleTextMessageReceived(textMessageArg); + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "Circle: " + circle.ToString() + "\r\nMember: " + member.ToString() + "\r\nSend you a text message:\r\n" + txtMessage.ToDebugString()); + + } + + if (mimeDic[MimeHeaderStrings.Content_Type].ToString().ToLowerInvariant().IndexOf("text/plain;") > -1 && + mimeDic[MimeHeaderStrings.Message_Type].ToString().ToLowerInvariant() == "nudge") + { + //Nudge + OnCircleNudgeReceived(arg); + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "Circle: " + circle.ToString() + "\r\nMember: " + member.ToString() + "\r\nSend you a nudge."); + } + } + } + } + } + + protected virtual void OnCircleTypingMessageReceived(CircleMemberEventArgs e) + { + if (CircleTypingMessageReceived != null) + CircleTypingMessageReceived(this, e); + } + + protected virtual void OnCircleNudgeReceived(CircleMemberEventArgs e) + { + if (CircleNudgeReceived != null) + CircleNudgeReceived(this, e); + } + + protected virtual void OnCircleTextMessageReceived(CircleTextMessageEventArgs e) + { + if (CircleTextMessageReceived != null) + CircleTextMessageReceived(this, e); + } + + protected virtual void OnLeftCircleConversation(CircleMemberEventArgs e) + { + if (LeftCircleConversation != null) + LeftCircleConversation(this, e); + } + + protected virtual void OnJoinedCircleConversation(CircleMemberEventArgs e) + { + if (JoinedCircleConversation != null) + JoinedCircleConversation(this, e); + } + + protected virtual void OnCircleStatusChanged(CircleStatusChangedEventArgs e) + { + if (CircleStatusChanged != null) + CircleStatusChanged(this, e); + } + + protected virtual void OnCircleMemberOnline(CircleMemberEventArgs e) + { + if (CircleMemberOnline != null) + CircleMemberOnline(this, e); + } + + protected virtual void OnCircleMemberOffline(CircleMemberEventArgs e) + { + if (CircleMemberOffline != null) + CircleMemberOffline(this, e); + } + + protected virtual void OnCircleMemberStatusChanged(CircleMemberStatusChanged e) + { + if (CircleMemberStatusChanged != null) + CircleMemberStatusChanged(this, e); + } + + protected virtual void OnCircleOnline(CircleEventArgs e) + { + if (CircleOnline != null) + CircleOnline(this, e); + } + + #endregion + + #region Challenge and Ping + + /// + /// Called when a CHL (challenge) command message has been received. + /// + /// + protected virtual void OnCHLReceived(NSMessage message) + { + if (Credentials == null) + throw new MSNPSharpException("No credentials available for the NSMSNP15 handler. No challenge answer could be send."); + + string payload = QRYFactory.CreateQRY(Credentials.ClientID, Credentials.ClientCode, message.CommandValues[0].ToString()); + MSNTicket.OIMLockKey = payload; + MessageProcessor.SendMessage(new NSPayLoadMessage("QRY", new string[] { Credentials.ClientID }, payload)); + } + + /// + /// Called when an PRP command has been received. + /// + /// + /// Informs about the phone numbers of the contact list owner. + /// PRP [TransactionID] [ListVersion] PhoneType Number + /// + /// + protected virtual void OnPRPReceived(NSMessage message) + { + string number = String.Empty; + string type = String.Empty; + if (message.CommandValues.Count >= 3) + { + number = MSNHttpUtility.NSDecode((string)message.CommandValues[2]); + type = message.CommandValues[1].ToString(); + } + else + { + number = MSNHttpUtility.NSDecode((string)message.CommandValues[1]); + type = message.CommandValues[0].ToString(); + } + + switch (type) + { + case "PHH": + ContactList.Owner.PhoneNumbers[ContactPhoneTypes.ContactPhonePersonal] = number; + break; + case "PHW": + ContactList.Owner.PhoneNumbers[ContactPhoneTypes.ContactPhoneBusiness] = number; + break; + case "PHM": + ContactList.Owner.PhoneNumbers[ContactPhoneTypes.ContactPhoneMobile] = number; + break; + case "MBE": + ContactList.Owner.SetMobileDevice((number == "Y") ? true : false); + break; + case "MOB": + ContactList.Owner.SetMobileAccess((number == "Y") ? true : false); + break; + case "MFN": + ContactList.Owner.SetName(MSNHttpUtility.NSDecode((string)message.CommandValues[1])); + break; + } + } + + /// + /// Called when a PUT command message has been received. + /// + /// + protected virtual void OnPUTReceived(NSMessage message) + { + } + + + /// + /// Called when a QRY (challenge) command message has been received. + /// + /// + protected virtual void OnQRYReceived(NSMessage message) + { + + } + + /// + /// Called when a QNG command has been received. + /// + /// + /// Indicates a ping answer. The number of seconds indicates the timespan in which another ping must be send. + /// QNG [Seconds] + /// + /// + protected virtual void OnQNGReceived(NSMessage message) + { + if (PingAnswer != null) + { + // get the number of seconds till the next ping and fire the event + // with the correct parameters. + int seconds = int.Parse((string)message.CommandValues[0], System.Globalization.CultureInfo.InvariantCulture); + PingAnswer(this, new PingAnswerEventArgs(seconds)); + + Interlocked.CompareExchange(ref canSendPing, 1, 0); + } + } + + + + #endregion + + #region Privacy + + /// + /// Called when a BLP command has been received. + /// + /// + /// Indicates that the server has send the privacy mode for the contact list owner. + /// BLP [Transaction] [SynchronizationID] [PrivacyMode] + /// + /// + protected virtual void OnBLPReceived(NSMessage message) + { + if (ContactList.Owner == null) + return; + + string type = message.CommandValues[0].ToString(); + + + switch (type) + { + case "AL": + ContactList.Owner.SetPrivacy(PrivacyMode.AllExceptBlocked); + if (AutoSynchronize) + { + ContactService.UpdateMe(); + } + break; + case "BL": + ContactList.Owner.SetPrivacy(PrivacyMode.NoneButAllowed); + if (AutoSynchronize) + { + ContactService.UpdateMe(); + } + break; + } + } + + /// + /// Called when a GCF command has been received. + /// + /// Indicates that the server has send bad words for messaging. + /// + protected virtual void OnGCFReceived(NSMessage message) + { + NetworkMessage networkMessage = message as NetworkMessage; + if (networkMessage.InnerBody != null) + { + censorWords.Clear(); + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.Load(new MemoryStream(networkMessage.InnerBody)); + XmlNodeList imtexts = xmlDoc.GetElementsByTagName("imtext"); + foreach (XmlNode imtextNode in imtexts) + { + string censor = Encoding.UTF8.GetString(Convert.FromBase64String(imtextNode.Attributes["value"].Value)); + censorWords.Add(new Regex(censor)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Censor: " + censor, GetType().Name); + } + } + } + + #endregion + + #endregion + + #region Command handler + + /// + /// Clears all resources associated with a nameserver session. + /// + /// + /// Called after we the processor has disconnected. This will clear the contactlist and free other resources. + /// + protected virtual bool Clear() + { + // 1. Cancel transfers + p2pHandler.Clear(); + + // 2. Cancel web services. MSNTicket must be here. + msnticket = MSNTicket.Empty; + ContactService.Clear(); + StorageService.Clear(); + OIMService.Clear(); + WhatsUpService.Clear(); + + // 3. isSignedIn must be here... + // a) ContactService.Clear() merges and saves addressbook if isSignedIn=true. + // b) Owner.ClientCapacities = ClientCapacities.None doesn't send CHG command if isSignedIn=false. + bool signedInStatus = IsSignedIn; + + isSignedIn = false; + externalEndPoint = null; + Interlocked.Exchange(ref canSendPing, 1); + + // 4. Clear contact lists and circle list. + ContactList.Reset(); + CircleList.Clear(); + ContactGroups.Clear(); + + //5. Reset contact manager. + Manager.Reset(); + + //6. Reset censor words + CensorWords.Clear(); + sessions.Clear(); + + //7. Unregister schedulers + Schedulers.P2PInvitationScheduler.UnRegister(P2PInvitationSchedulerId); + Schedulers.SwitchBoardRequestScheduler.UnRegister(SwitchBoardRequestSchedulerId); + + return signedInStatus; + } + + protected virtual NetworkMessage ParseTextPayloadMessage(NSMessage message) + { + TextPayloadMessage txtPayLoad = new TextPayloadMessage(string.Empty); + txtPayLoad.CreateFromParentMessage(message); + return message; + } + + protected virtual NetworkMessage ParseMSGMessage(NSMessage message) + { + MimeMessage mimeMessage = new MimeMessage(); + mimeMessage.CreateFromParentMessage(message); + + string mime = mimeMessage.MimeHeader[MimeHeaderStrings.Content_Type].ToString(); + + if (mime.IndexOf("text/x-msmsgsprofile") >= 0) + { + //This is profile, the content is nothing. + } + else + { + MimeMessage innerMimeMessage = new MimeMessage(false); + innerMimeMessage.CreateFromParentMessage(mimeMessage); + } + + return message; + } + + protected virtual NetworkMessage ParseUBMMessage(NSMessage message) + { + MimeMessage mimeMessage = new MimeMessage(); + mimeMessage.CreateFromParentMessage(message); + + if (mimeMessage.MimeHeader.ContainsKey(MimeHeaderStrings.Content_Type)) + { + switch (mimeMessage.MimeHeader[MimeHeaderStrings.Content_Type]) + { + case "text/x-msmsgscontrol": + { + TextPayloadMessage txtPayload = new TextPayloadMessage(string.Empty); + txtPayload.CreateFromParentMessage(mimeMessage); + break; + } + case "text/x-msnmsgr-datacast": + { + TextPayloadMessage txtPayload = new TextPayloadMessage(string.Empty); + txtPayload.CreateFromParentMessage(mimeMessage); + + if (txtPayload.Text.IndexOf("ID:") != -1) + { + MimeMessage innerMime = new MimeMessage(); + innerMime.CreateFromParentMessage(mimeMessage); + } + break; + } + + } + + if (mimeMessage.MimeHeader[MimeHeaderStrings.Content_Type].ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf("text/plain") >= 0) + { + TextMessage txtMessage = new TextMessage(); + txtMessage.CreateFromParentMessage(mimeMessage); + } + } + else + { + + TextPayloadMessage txtPayLoad = new TextPayloadMessage(string.Empty); + txtPayLoad.CreateFromParentMessage(message); + } + + return message; + } + + protected virtual NetworkMessage ParseNetworkMessage(NetworkMessage message) + { + NSMessage nsMessage = (NSMessage)message; + + if (nsMessage.InnerBody != null) + { + switch (nsMessage.Command) + { + case "MSG": + ParseMSGMessage(nsMessage); + break; + case "UBM": + ParseUBMMessage(nsMessage); + break; + default: + ParseTextPayloadMessage(nsMessage); + break; + } + } + + return nsMessage; + } + + protected virtual bool ProcessNetworkMessage(NetworkMessage message) + { + NSMessage nsMessage = (NSMessage)message; + bool isUnknownMessage = false; + + switch (nsMessage.Command) + { + // Most used CMDs + case "MSG": + OnMSGReceived(nsMessage); + break; + case "FLN": + OnFLNReceived(nsMessage); + break; + case "NLN": + OnNLNReceived(nsMessage); + break; + case "QNG": + OnQNGReceived(nsMessage); + break; + case "UBX": + OnUBXReceived(nsMessage); + break; + + // Other CMDs + case "ADG": + OnADGReceived(nsMessage); + break; + case "ADL": + OnADLReceived(nsMessage); + break; + case "BLP": + OnBLPReceived(nsMessage); + break; + case "CHG": + OnCHGReceived(nsMessage); + break; + case "CHL": + OnCHLReceived(nsMessage); + break; + case "CVR": + OnCVRReceived(nsMessage); + break; + case "FQY": + OnFQYReceived(nsMessage); + break; + case "GCF": + OnGCFReceived(nsMessage); + break; + case "NOT": + OnNOTReceived(nsMessage); + break; + case "OUT": + OnOUTReceived(nsMessage); + break; + case "PRP": + OnPRPReceived(nsMessage); + break; + case "QRY": + OnQRYReceived(nsMessage); + break; + case "RMG": + OnRMGReceived(nsMessage); + break; + case "RML": + OnRMLReceived(nsMessage); + break; + case "RNG": + OnRNGReceived(nsMessage); + break; + case "UBM": + OnUBMReceived(nsMessage); + break; + case "UBN": + OnUBNReceived(nsMessage); + break; + case "USR": + OnUSRReceived(nsMessage); + break; + case "UUN": + OnUUNReceived(nsMessage); + break; + case "UUX": + OnUUXReceived(nsMessage); + break; + case "VER": + OnVERReceived(nsMessage); + break; + case "XFR": + OnXFRReceived(nsMessage); + break; + case "SBS": + OnSBSReceived(nsMessage); + break; + case "NFY": + OnNFYReceived(nsMessage); + break; + case "PUT": + OnPUTReceived(nsMessage); + break; + case "SDG": + OnSDGReceived(nsMessage); + break; + default: + isUnknownMessage = true; + break; + } + + return !isUnknownMessage; + } + + /// + /// Handles message from the processor. + /// + /// + /// This is one of the most important functions of the class. + /// It handles incoming messages and performs actions based on the commands in the messages. + /// Many commands will affect the data objects in MSNPSharp, like and . + /// For example contacts are renamed, contactgroups are added and status is set. + /// Exceptions which occur in this method are redirected via the event. + /// + /// The message processor that dispatched the message. + /// The network message received from the notification server + public virtual void HandleMessage(IMessageProcessor sender, NetworkMessage message) + { + try + { + // We expect at least a NSMessage object + NSMessage nsMessage = (NSMessage)message; + bool processed = false; + + ParseNetworkMessage(message); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Incoming NS command: " + message.ToDebugString() + "\r\n", GetType().Name); + + processed = ProcessNetworkMessage(message); + + if (processed) + return; + + // Check whether it is a numeric error command + if (nsMessage.Command[0] >= '0' && nsMessage.Command[0] <= '9' && processed == false) + { + MSNError msnError = 0; + try + { + int errorCode = int.Parse(nsMessage.Command, System.Globalization.CultureInfo.InvariantCulture); + msnError = (MSNError)errorCode; + } + catch (Exception fe) + { + throw new MSNPSharpException("Exception Occurred when parsing an error code received from the server", fe); + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "A server error occurred\r\nError Code: " + nsMessage.Command + + "\r\nError Description: " + msnError.ToString()); + + OnServerErrorReceived(new MSNErrorEventArgs(msnError)); + } + else + { + // It is a unknown command + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "UNKNOWN COMMAND: " + nsMessage.Command + "\r\n" + nsMessage.ToDebugString(), GetType().ToString()); + } + } + catch (Exception e) + { + OnExceptionOccurred(new ExceptionEventArgs(e)); + throw; //RethrowToPreserveStackDetails (without e) + } + } + + /// + /// Fires the event. + /// + /// + protected virtual void OnServerErrorReceived(MSNErrorEventArgs e) + { + if (ServerErrorReceived != null) + ServerErrorReceived(this, e); + } + + /// + /// Fires the event. + /// + /// The exception event args + protected virtual void OnExceptionOccurred(ExceptionEventArgs e) + { + if (ExceptionOccurred != null) + ExceptionOccurred(this, e); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, e.Exception.Message + "\r\n\r\nStackTrace: \r\n" + e.Exception.StackTrace + "\r\n\r\n", GetType().Name); + } + + /// + /// Fires the event. + /// + /// The exception event args + protected virtual void OnAuthenticationErrorOccurred(ExceptionEventArgs e) + { + if (AuthenticationError != null) + AuthenticationError(this, e); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, e.ToString(), GetType().Name); + } + + /// + /// Fires the event. + /// + protected virtual void OnOwnerVerified() + { + if (OwnerVerified != null) + OwnerVerified(this, new EventArgs()); + } + + #endregion + } +}; diff --git a/MSNPSharp/NSMessageProcessor.cs b/MSNPSharp/NSMessageProcessor.cs new file mode 100644 index 0000000..b66589a --- /dev/null +++ b/MSNPSharp/NSMessageProcessor.cs @@ -0,0 +1,146 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Text; +using System.Collections; +using System.Diagnostics; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + public class NSMessageProcessor : SocketMessageProcessor + { + private int transactionID = 0; + + public event EventHandler HandlerException; + + protected internal NSMessageProcessor(ConnectivitySettings connectivitySettings) + : base(connectivitySettings) + { + MessagePool = new NSMessagePool(); + } + + public int TransactionID + { + get + { + return transactionID; + } + private set + { + transactionID = value; + } + } + + /// + /// Reset the transactionID to zero. + /// + internal void ResetTransactionID() + { + TransactionID = 0; + } + + protected internal int IncreaseTransactionID() + { + return ++transactionID; + } + + protected override void OnMessageReceived(byte[] data) + { + NSMessage message = new NSMessage(); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Parsing incoming NS command...", GetType().Name); + message.ParseBytes(data); + DispatchMessage(message); + } + + public override void SendMessage(NetworkMessage message) + { + SendMessage(message, IncreaseTransactionID()); + } + + public virtual void SendMessage(NetworkMessage message, int transactionID) + { + NSMessage nsMessage = message as NSMessage; + + if (nsMessage == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "Cannot use this Message Processor to send a " + message.GetType().ToString() + " message.", + GetType().Name); + return; + } + + nsMessage.TransactionID = transactionID; + nsMessage.PrepareMessage(); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Outgoing message:\r\n" + nsMessage.ToDebugString() + "\r\n", GetType().Name); + + // convert to bytes and send it over the socket + SendSocketData(nsMessage.GetBytes()); + } + + public override void Disconnect() + { + SendMessage(new NSMessage("OUT", new string[] { })); + base.Disconnect(); + } + + protected virtual void DispatchMessage(NetworkMessage message) + { + // copy the messageHandlers array because the collection can be + // modified during the message handling. (Handlers are registered/unregistered) + IMessageHandler[] handlers = MessageHandlers.ToArray(); + + // now give the handlers the opportunity to handle the message + foreach (IMessageHandler handler in handlers) + { + try + { + //I think the person who first write this make a big mistake, C# is NOT C++, + //message class passes as reference, one change, all changed. + //Mabe we need to review all HandleMessage calling. + ICloneable imessageClone = (message as NSMessage) as ICloneable; + NSMessage messageClone = imessageClone.Clone() as NSMessage; + handler.HandleMessage(this, messageClone); + } + catch (Exception e) + { + if (HandlerException != null) + HandlerException(this, new ExceptionEventArgs(new MSNPSharpException("An exception occured while handling a nameserver message. See inner exception for more details.", e))); + } + } + } + } +}; diff --git a/MSNPSharp/Owner.cs b/MSNPSharp/Owner.cs new file mode 100644 index 0000000..36ba81a --- /dev/null +++ b/MSNPSharp/Owner.cs @@ -0,0 +1,910 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Net; +using System.Drawing; +using System.Reflection; +using System.Collections; +using System.Diagnostics; +using System.Collections.Generic; + +namespace MSNPSharp +{ + using MSNPSharp.IO; + using MSNPSharp.Core; + using System.IO; + + + [Serializable] + public class Owner : Contact + { + /// + /// Fired when owner places changed. + /// + public event EventHandler PlacesChanged; + + + private string epName = Environment.MachineName; + + private bool passportVerified; + private PrivacyMode privacy = PrivacyMode.Unknown; + private NotifyPrivacy notifyPrivacy = NotifyPrivacy.Unknown; + private RoamLiveProperty roamLiveProperty = RoamLiveProperty.Unspecified; + + public Owner(string abId, string account, long cid, NSMessageHandler handler) + : base(abId, account, ClientType.PassportMember, cid, handler) + { + } + + public Owner(Guid abId, string account, long cid, NSMessageHandler handler) + : base(abId, account, ClientType.PassportMember, cid, handler) + { + } + + protected override void Initialized(Guid abId, string account, ClientType cliType, long cid, NSMessageHandler handler) + { + base.Initialized(abId, account, cliType, cid, handler); + + EndPointData.Clear(); + EndPointData.Add(Guid.Empty, new PrivateEndPointData(account, Guid.Empty)); + EndPointData.Add(NSMessageHandler.MachineGuid, new PrivateEndPointData(account, NSMessageHandler.MachineGuid)); + } + + /// + /// Called when the End Points changed. + /// + /// + protected virtual void OnPlacesChanged(PlaceChangedEventArgs e) + { + if (PlacesChanged != null) + PlacesChanged(this, e); + } + + + /// + /// Fired when owner profile received. + /// + public event EventHandler ProfileReceived; + + internal void CreateDefaultDisplayImage(SerializableMemoryStream sms) + { + if (sms == null) + { + sms = new SerializableMemoryStream(); + Image msnpsharpDefaultImage = Properties.Resources.MSNPSharp_logo.Clone() as Image; + msnpsharpDefaultImage.Save(sms, msnpsharpDefaultImage.RawFormat); + } + + DisplayImage displayImage = new DisplayImage(Mail.ToLowerInvariant(), sms); + + this.DisplayImage = displayImage; + } + + internal void SetPrivacy(PrivacyMode mode) + { + privacy = mode; + } + + internal void SetNotifyPrivacy(NotifyPrivacy mode) + { + notifyPrivacy = mode; + } + + internal void SetRoamLiveProperty(RoamLiveProperty mode) + { + roamLiveProperty = mode; + } + + internal void SetChangedPlace(Guid epId, string placeName, PlaceChangedReason action) + { + bool triggerEvent = false; + lock (SyncObject) + { + switch (action) + { + case PlaceChangedReason.SignedIn: + if (!EndPointData.ContainsKey(epId)) + { + PrivateEndPointData newEndPoint = new PrivateEndPointData(Mail, epId); + newEndPoint.Name = placeName; + EndPointData[epId] = newEndPoint; + triggerEvent = true; + } + break; + + case PlaceChangedReason.SignedOut: + if (EndPointData.ContainsKey(epId)) + { + EndPointData.Remove(epId); + triggerEvent = true; + } + break; + } + + } + + if (triggerEvent) + { + OnPlacesChanged(new PlaceChangedEventArgs(epId, placeName, action)); + } + } + + /// + /// This place's name + /// + public string EpName + { + get + { + return epName; + } + set + { + epName = value; + + if (NSMessageHandler != null && NSMessageHandler.IsSignedIn && Status != PresenceStatus.Offline) + { + NSMessageHandler.SetPresenceStatusUUX(Status); + } + } + } + + /// + /// Get or set the of local end point. + /// + public ClientCapacities LocalEndPointClientCapacities + { + get + { + if (EndPointData.ContainsKey(NSMessageHandler.MachineGuid)) + return EndPointData[NSMessageHandler.MachineGuid].ClientCapacities; + + return ClientCapacities.None; + } + + set + { + if (value != LocalEndPointClientCapacities) + { + EndPointData[NSMessageHandler.MachineGuid].ClientCapacities = value; + BroadcastDisplayImage(); + } + } + } + + /// + /// Get or set the of local end point. + /// + public ClientCapacitiesEx LocalEndPointClientCapacitiesEx + { + get + { + if (EndPointData.ContainsKey(NSMessageHandler.MachineGuid)) + return EndPointData[NSMessageHandler.MachineGuid].ClientCapacitiesEx; + + return ClientCapacitiesEx.None; + } + + set + { + if (value != LocalEndPointClientCapacitiesEx) + { + EndPointData[NSMessageHandler.MachineGuid].ClientCapacitiesEx = value; + BroadcastDisplayImage(); + } + } + } + + /// + /// Sign the owner out from every place. + /// + public void SignoutFromEverywhere() + { + Status = PresenceStatus.Hidden; + NSMessageHandler.MessageProcessor.SendMessage(new NSPayLoadMessage("UUN", new string[] { Mail, "8" }, "gtfo")); + Status = PresenceStatus.Offline; + } + + /// + /// Sign the owner out from the specificed place. + /// + /// The EndPoint guid to be signed out + public void SignoutFrom(Guid endPointID) + { + if (endPointID == Guid.Empty) + { + SignoutFromEverywhere(); + return; + } + + if (EndPointData.ContainsKey(endPointID)) + { + NSMessageHandler.MessageProcessor.SendMessage(new NSPayLoadMessage("UUN", + new string[] { Mail + ";" + endPointID.ToString("B").ToLowerInvariant(), "4" }, "goawyplzthxbye" + (MPOPMode == MPOP.AutoLogoff ? "-nomorempop" : String.Empty))); + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "Invalid place (signed out already): " + endPointID.ToString("B"), GetType().Name); + } + } + + /// + /// Owner display image. The image is broadcasted automatically. + /// + public override DisplayImage DisplayImage + { + get + { + return base.DisplayImage; + } + + internal set + { + if (value != null) + { + if (base.DisplayImage != null) + { + if (value.Sha == base.DisplayImage.Sha) + { + return; + } + + MSNObjectCatalog.GetInstance().Remove(base.DisplayImage); + } + + SetDisplayImageAndFireDisplayImageChangedEvent(value); + value.Creator = Mail; + + MSNObjectCatalog.GetInstance().Add(base.DisplayImage); + + BroadcastDisplayImage(); + } + } + } + + /// + /// Personel message + /// + public new PersonalMessage PersonalMessage + { + get + { + return base.PersonalMessage; + } + set + { + if (NSMessageHandler != null) + { + NSMessageHandler.SetPersonalMessage(value); + } + + if (value != null) + base.SetPersonalMessage(value); + } + } + + + internal void BroadcastDisplayImage() + { + if (NSMessageHandler != null && NSMessageHandler.IsSignedIn && Status != PresenceStatus.Offline && Status != PresenceStatus.Unknown) + { + // Resend the user status so other client can see the new msn object + + string capacities = ((long)LocalEndPointClientCapacities).ToString() + ":" + ((long)LocalEndPointClientCapacitiesEx).ToString(); + + string context = "0"; + + if (DisplayImage != null && DisplayImage.Image != null) + context = DisplayImage.Context; + + NSMessageHandler.MessageProcessor.SendMessage(new NSMessage("CHG", new string[] { NSMessageHandler.ParseStatus(Status), capacities, context })); + } + } + + public new string MobilePhone + { + get + { + return base.MobilePhone; + } + set + { + if (NSMessageHandler != null) + { + NSMessageHandler.SetPhoneNumberMobile(value); + } + } + } + + public new string WorkPhone + { + get + { + return base.WorkPhone; + } + set + { + if (NSMessageHandler != null) + { + NSMessageHandler.SetPhoneNumberWork(value); + } + } + } + + public new string HomePhone + { + get + { + return base.HomePhone; + } + set + { + if (NSMessageHandler != null) + { + NSMessageHandler.SetPhoneNumberHome(value); + } + } + } + + public new bool MobileDevice + { + get + { + return base.MobileDevice; + } + // it seems the server does not like it when we want to set mobile device ourselves! + /*set + { + if(nsMessageHandler != null) + { + nsMessageHandler.SetMobileDevice(value); + } + }*/ + } + + public new bool MobileAccess + { + get + { + return base.MobileAccess; + } + set + { + if (NSMessageHandler != null) + { + NSMessageHandler.SetMobileAccess(value); + } + } + } + + /// + /// Whether this account is verified by email. If an account is not verified, "(email not verified)" will be displayed after a contact's displayname. + /// + public bool PassportVerified + { + get + { + return passportVerified; + } + internal set + { + passportVerified = value; + } + } + + public PrivacyMode Privacy + { + get + { + return privacy; + } + set + { + if (NSMessageHandler != null) + { + NSMessageHandler.SetPrivacyMode(value); + } + } + } + + public NotifyPrivacy NotifyPrivacy + { + get + { + return notifyPrivacy; + } + set + { + if (NSMessageHandler != null) + { + NSMessageHandler.SetNotifyPrivacyMode(value); + } + } + } + + public RoamLiveProperty RoamLiveProperty + { + get + { + return roamLiveProperty; + } + set + { + roamLiveProperty = value; + if (NSMessageHandler != null) + { + NSMessageHandler.ContactService.UpdateMe(); + } + } + } + + bool mpopEnabled; + MPOP mpopMode = MPOP.Unspecified; + string _routeInfo = string.Empty; + + /// + /// Route address, used for PNRP?? + /// + public string RouteInfo + { + get + { + return _routeInfo; + } + internal set + { + _routeInfo = value; + } + } + + /// + /// Whether the contact list owner has Multiple Points of Presence Support (MPOP) that is owner connect from multiple places. + /// + public bool MPOPEnable + { + get + { + return mpopEnabled; + } + internal set + { + mpopEnabled = value; + } + } + + + internal void SetMPOP(MPOP mpop) + { + MPOPMode = mpop; + } + + /// + /// Reaction when sign in at another place. + /// + public MPOP MPOPMode + { + get + { + if (mpopMode == MPOP.Unspecified && mpopEnabled) //If unspecified, we get it from profile. + { + if (NSMessageHandler != null) + { + if (NSMessageHandler.ContactService.AddressBook != null) + { + if (NSMessageHandler.ContactService.AddressBook.MyProperties.ContainsKey(AnnotationNames.MSN_IM_MPOP)) + mpopMode = NSMessageHandler.ContactService.AddressBook.MyProperties[AnnotationNames.MSN_IM_MPOP] == "1" ? MPOP.KeepOnline : MPOP.AutoLogoff; + + } + } + } + return mpopMode; + } + set + { + if (NSMessageHandler != null && MPOPEnable) + { + mpopMode = value; + NSMessageHandler.ContactService.UpdateMe(); + } + } + } + + public override PresenceStatus Status + { + get + { + return base.Status; + } + + set + { + if (NSMessageHandler != null) + { + NSMessageHandler.SetPresenceStatus(value); + } + + if (PersonalMessage != null) + { + (EndPointData[MachineGuid] as PrivateEndPointData).State = base.Status; + } + else + { + (EndPointData[NSMessageHandler.MachineGuid] as PrivateEndPointData).State = base.Status; + } + } + } + + public override string Name + { + get + { + return string.IsNullOrEmpty(base.Name) ? NickName : base.Name; + } + + set + { + if (Name == value) return; + if (NSMessageHandler != null) + { + NSMessageHandler.SetScreenName(value); + } + } + } + + + #region Profile datafields + bool validProfile; + string loginTime; + bool emailEnabled; + string memberIdHigh; + string memberIdLowd; + string preferredLanguage; + string preferredMail; + string country; + string postalCode; + string gender; + string kid; + string age; + string birthday; + string wallet; + string sid; + string kV; + string mSPAuth; + IPAddress clientIP; + int clientPort; + + public bool ValidProfile + { + get + { + return validProfile; + } + internal set + { + validProfile = value; + } + } + + public string LoginTime + { + get + { + return loginTime; + } + set + { + loginTime = value; + } + } + + public bool EmailEnabled + { + get + { + return emailEnabled; + } + set + { + emailEnabled = value; + } + } + + public string MemberIdHigh + { + get + { + return memberIdHigh; + } + set + { + memberIdHigh = value; + } + } + + public string MemberIdLowd + { + get + { + return memberIdLowd; + } + set + { + memberIdLowd = value; + } + } + + public string PreferredLanguage + { + get + { + return preferredLanguage; + } + set + { + preferredLanguage = value; + } + } + + public string PreferredMail + { + get + { + return preferredMail; + } + set + { + preferredMail = value; + } + } + + public string Country + { + get + { + return country; + } + set + { + country = value; + } + } + + public string PostalCode + { + get + { + return postalCode; + } + set + { + postalCode = value; + } + } + + public string Gender + { + get + { + return gender; + } + set + { + gender = value; + } + } + + public string Kid + { + get + { + return kid; + } + set + { + kid = value; + } + } + + public string Age + { + get + { + return age; + } + set + { + age = value; + } + } + + public string Birthday + { + get + { + return birthday; + } + set + { + birthday = value; + } + } + + + public string Wallet + { + get + { + return wallet; + } + set + { + wallet = value; + } + } + + public string Sid + { + get + { + return sid; + } + set + { + sid = value; + } + } + + public string KV + { + get + { + return kV; + } + set + { + kV = value; + } + } + + public string MSPAuth + { + get + { + return mSPAuth; + } + set + { + mSPAuth = value; + } + } + + public IPAddress ClientIP + { + get + { + return clientIP; + } + set + { + clientIP = value; + } + } + + public int ClientPort + { + get + { + return clientPort; + } + set + { + clientPort = value; + } + } + + #endregion + + /// + /// This will update the profile of the Owner object. + /// + /// This method fires the event. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + internal void UpdateProfile( + string loginTime, bool emailEnabled, string memberIdHigh, + string memberIdLowd, string preferredLanguage, string preferredMail, + string country, string postalCode, string gender, + string kid, string age, string birthday, + string wallet, string sid, string kv, + string mspAuth, IPAddress clientIP, int clientPort, + string nick, + bool mpop, + string routeInfo) + { + LoginTime = loginTime; + EmailEnabled = emailEnabled; + MemberIdHigh = memberIdHigh; + MemberIdLowd = memberIdLowd; + PreferredLanguage = preferredLanguage; + PreferredMail = preferredMail; + Country = country; + PostalCode = postalCode; + Gender = gender; + Kid = kid; + Age = age; + Birthday = birthday; + Wallet = wallet; + Sid = sid; + KV = kv; + MSPAuth = mspAuth; + ClientIP = clientIP; + ClientPort = clientPort; + MPOPEnable = mpop; + RouteInfo = routeInfo; + SetNickName(nick); + ValidProfile = true; + + OnProfileReceived(EventArgs.Empty); + } + + /// + /// Called when the server has send a profile description. + /// + /// + protected virtual void OnProfileReceived(EventArgs e) + { + if (ProfileReceived != null) + ProfileReceived(this, e); + } + + } +}; diff --git a/MSNPSharp/PersonalMessage.cs b/MSNPSharp/PersonalMessage.cs new file mode 100644 index 0000000..2e5fa5a --- /dev/null +++ b/MSNPSharp/PersonalMessage.cs @@ -0,0 +1,291 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Web; +using System.Xml; +using System.Text; +using System.Text.RegularExpressions; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + [Serializable()] + public class PersonalMessage + { + private string personalMessage; + private Guid machineGuid; + + private string signatureSound; + + private string appName; + private string format; + private MediaType mediaType; + + [NonSerialized] + private NSMessage nsMessage; + + private string[] content; + + public PersonalMessage(string personalmsg, MediaType mediatype, string[] currentmediacontent, Guid machineguid) + { + Message = personalmsg; + mediaType = mediatype; + content = currentmediacontent; + machineGuid = machineguid; + Format = "{0}"; + } + + public PersonalMessage(string personalmsg, MediaType mediatype, string[] currentmediacontent, string contentformat, Guid machineguid) + { + Message = personalmsg; + mediaType = mediatype; + content = currentmediacontent; + machineGuid = machineguid; + Format = contentformat; + } + + internal PersonalMessage(NSMessage message) + { + nsMessage = message; + mediaType = MediaType.None; + machineGuid = Guid.Empty; + + try + { + Handle(); + } + catch (Exception exception) + { + System.Diagnostics.Trace.WriteLineIf(Settings.TraceSwitch.TraceError, exception.Message, GetType().Name); + } + } + + public NSMessage NSMessage + { + get + { + return nsMessage; + } + } + + public string Payload + { + get + { + string currentmedia = String.Empty; + + if (mediaType != MediaType.None) + { + foreach (string media in content) + { + currentmedia = currentmedia + media + @"\0"; + } + + if (Format == null || Format == "" || Format == String.Empty) + Format = "{0}"; + + currentmedia = @"\0" + mediaType.ToString() + @"\01\0" + Format + @"\0" + currentmedia; + } + + string pload = String.Format( + "{0}{1}" + + "{2}" + + "{3}" + + "", + MSNHttpUtility.XmlEncode(personalMessage), + MSNHttpUtility.XmlEncode(currentmedia), + MSNHttpUtility.XmlEncode(machineGuid.ToString("B")), + MSNHttpUtility.XmlEncode(signatureSound)); + + return pload; + } + } + + public string Message + { + get + { + return personalMessage; + } + set + { + personalMessage = value; + } + } + + public Guid MachineGuid + { + get + { + return machineGuid; + } + } + + public string SignatureSound + { + get + { + return signatureSound; + } + } + + public MediaType MediaType + { + get + { + return mediaType; + } + } + + public string AppName + { + get + { + return appName; + } + } + + public string Format + { + get + { + return format; + } + set + { + format = value; + } + } + + //This is used in conjunction with format + public string[] CurrentMediaContent + { + get + { + return content; + } + set + { + content = value; + } + } + + public string ToDebugString() + { + return System.Text.UTF8Encoding.UTF8.GetString(nsMessage.InnerBody); + } + + public override string ToString() + { + return personalMessage; + } + + private void Handle() + { + if (nsMessage.InnerBody == null) + return; + + XmlDocument xmlDoc = new XmlDocument(); + MemoryStream ms = new MemoryStream(nsMessage.InnerBody); + TextReader reader = new StreamReader(ms, new System.Text.UTF8Encoding(false)); + + xmlDoc.Load(reader); + + XmlNode node = xmlDoc.SelectSingleNode("//Data/PSM"); + if (node != null) + { + personalMessage = System.Web.HttpUtility.UrlDecode(node.InnerText, System.Text.Encoding.UTF8); + } + + node = xmlDoc.SelectSingleNode("//Data/CurrentMedia"); + if (node != null) + { + string cmedia = System.Web.HttpUtility.UrlDecode(node.InnerText, System.Text.Encoding.UTF8); + + if (cmedia.Length > 0) + { + string[] vals = cmedia.Split(new string[] { @"\0" }, StringSplitOptions.None); + + if (vals[0] != "") + appName = vals[0]; + + switch (vals[1]) + { + case "Music": + mediaType = MediaType.Music; + break; + case "Games": + mediaType = MediaType.Games; + break; + case "Office": + mediaType = MediaType.Office; + break; + } + + /* + 0 + 1 Music + 2 1 + 3 {0} - {1} + 4 Evanescence + 5 Call Me When You're Sober + 6 Album + 7 WMContentID + 8 + */ + //vals[2] = Enabled/Disabled + + format = vals[3]; + + int size = vals.Length - 4; + + content = new String[size]; + + for (int i = 0; i < size; i++) + content[i] = vals[i + 4]; + } + } + + node = xmlDoc.SelectSingleNode("//Data/MachineGuid"); + if (node != null && node.InnerText != String.Empty) + machineGuid = new Guid(node.InnerText); + + node = xmlDoc.SelectSingleNode("//Data/SignatureSound"); + if (node != null) + signatureSound = node.InnerText; + + } + } +}; \ No newline at end of file diff --git a/MSNPSharp/Properties/AssemblyInfo.cs b/MSNPSharp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..aa98ced --- /dev/null +++ b/MSNPSharp/Properties/AssemblyInfo.cs @@ -0,0 +1,26 @@ +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: CLSCompliantAttribute(false)] +[assembly: AssemblyTitleAttribute("MSNPSharp MSN Protocol Library")] +[assembly: AssemblyDescriptionAttribute("C# implementation of the MSN protocol")] +[assembly: AssemblyCopyrightAttribute("Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice.")] +[assembly: AssemblyProductAttribute("MSNPSharp")] +[assembly: AssemblyDelaySignAttribute(false)] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisibleAttribute(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: GuidAttribute("FAE04EC0-301F-11D3-BF4B-00C04F79EFBC")] + +// Version information for an assembly consists of the following four values: +// Major.Minor.Build.SVNRevision +[assembly: AssemblyVersionAttribute("3.2.1.2668")] +[assembly: AssemblyFileVersionAttribute("3.2.1.2668")] +[assembly: AssemblyCompanyAttribute("MSNPSharp")] +[assembly: AssemblyTrademarkAttribute("MSNPSharp")] diff --git a/MSNPSharp/Properties/Resources.Designer.cs b/MSNPSharp/Properties/Resources.Designer.cs new file mode 100644 index 0000000..ff96af7 --- /dev/null +++ b/MSNPSharp/Properties/Resources.Designer.cs @@ -0,0 +1,128 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MSNPSharp.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MSNPSharp.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Messenger Client 9.0. + /// + internal static string ApplicationStrId { + get { + return ResourceManager.GetString("ApplicationStrId", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 3.2.1.2668. + /// + internal static string DeltasListVersion { + get { + return ResourceManager.GetString("DeltasListVersion", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap MSNPSharp_logo { + get { + object obj = ResourceManager.GetObject("MSNPSharp_logo", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to MSN Explorer/9.0 (MSN 8.0; TmstmpExt). + /// + internal static string WebServiceUserAgent { + get { + return ResourceManager.GetString("WebServiceUserAgent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 3B119D87-1D76-4474-91AD-0D7267E86D04. + /// + internal static string WhatsupServiceAppID { + get { + return ResourceManager.GetString("WhatsupServiceAppID", resourceCulture); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap WLXLarge_default { + get { + object obj = ResourceManager.GetObject("WLXLarge_default", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized string similar to 3.2.1.2668. + /// + internal static string XMLContactListVersion { + get { + return ResourceManager.GetString("XMLContactListVersion", resourceCulture); + } + } + } +} diff --git a/MSNPSharp/Properties/Resources.resx b/MSNPSharp/Properties/Resources.resx new file mode 100644 index 0000000..c696dff --- /dev/null +++ b/MSNPSharp/Properties/Resources.resx @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Messenger Client 9.0 + + + 3.2.1.2668 + + + + ..\Resources\MSNPSharp_logo_128.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + MSN Explorer/9.0 (MSN 8.0; TmstmpExt) + + + 3B119D87-1D76-4474-91AD-0D7267E86D04 + + + ..\Resources\WLXLarge_default.gif;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + 3.2.1.2668 + + \ No newline at end of file diff --git a/MSNPSharp/ProxySocket/AuthMethod.cs b/MSNPSharp/ProxySocket/AuthMethod.cs new file mode 100644 index 0000000..ee820fb --- /dev/null +++ b/MSNPSharp/ProxySocket/AuthMethod.cs @@ -0,0 +1,113 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; + +namespace Org.Mentalis.Network.ProxySocket.Authentication { + /// + /// Implements a SOCKS authentication scheme. + /// + /// This is an abstract class; it must be inherited. + internal abstract class AuthMethod { + /// + /// Initializes an AuthMethod instance. + /// + /// The socket connection with the proxy server. + public AuthMethod(Socket server) { + Server = server; + } + /// + /// Authenticates the user. + /// + /// Authentication with the proxy server failed. + /// The proxy server uses an invalid protocol. + /// An operating system error occurs while accessing the Socket. + /// The Socket has been closed. + public abstract void Authenticate(); + /// + /// Authenticates the user asynchronously. + /// + /// The method to call when the authentication is complete. + /// Authentication with the proxy server failed. + /// The proxy server uses an invalid protocol. + /// An operating system error occurs while accessing the Socket. + /// The Socket has been closed. + public abstract void BeginAuthenticate(HandShakeComplete callback); + /// + /// Gets or sets the socket connection with the proxy server. + /// + /// The socket connection with the proxy server. + protected Socket Server { + get { + return m_Server; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_Server = value; + } + } + /// + /// Gets or sets a byt array that can be used to store data. + /// + /// A byte array to store data. + protected byte[] Buffer { + get { + return m_Buffer; + } + set { + m_Buffer = value; + } + } + /// + /// Gets or sets the number of bytes that have been received from the remote proxy server. + /// + /// An integer that holds the number of bytes that have been received from the remote proxy server. + protected int Received { + get { + return m_Received; + } + set { + m_Received = value; + } + } + // private variables + /// Holds the value of the Buffer property. + private byte[] m_Buffer; + /// Holds the value of the Server property. + private Socket m_Server; + /// Holds the address of the method to call when the proxy has authenticated the client. + protected HandShakeComplete CallBack; + /// Holds the value of the Received property. + private int m_Received; + } +} \ No newline at end of file diff --git a/MSNPSharp/ProxySocket/AuthNone.cs b/MSNPSharp/ProxySocket/AuthNone.cs new file mode 100644 index 0000000..ac5a91f --- /dev/null +++ b/MSNPSharp/ProxySocket/AuthNone.cs @@ -0,0 +1,60 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; + +namespace Org.Mentalis.Network.ProxySocket.Authentication { + /// + /// This class implements the 'No Authentication' scheme. + /// + internal sealed class AuthNone : AuthMethod { + /// + /// Initializes an AuthNone instance. + /// + /// The socket connection with the proxy server. + public AuthNone(Socket server) : base(server) {} + /// + /// Authenticates the user. + /// + public override void Authenticate() { + return; // Do Nothing + } + /// + /// Authenticates the user asynchronously. + /// + /// The method to call when the authentication is complete. + /// This method immediately calls the callback method. + public override void BeginAuthenticate(HandShakeComplete callback) { + callback(null); + } + } +} \ No newline at end of file diff --git a/MSNPSharp/ProxySocket/AuthUserPass.cs b/MSNPSharp/ProxySocket/AuthUserPass.cs new file mode 100644 index 0000000..732e502 --- /dev/null +++ b/MSNPSharp/ProxySocket/AuthUserPass.cs @@ -0,0 +1,157 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; + +namespace Org.Mentalis.Network.ProxySocket.Authentication { + /// + /// This class implements the 'username/password authentication' scheme. + /// + internal sealed class AuthUserPass : AuthMethod { + /// + /// Initializes a new AuthUserPass instance. + /// + /// The socket connection with the proxy server. + /// The username to use. + /// The password to use. + /// user -or- pass is null. + public AuthUserPass(Socket server, string user, string pass) : base(server) { + Username = user; + Password = pass; + } + /// + /// Creates an array of bytes that has to be sent if the user wants to authenticate with the username/password authentication scheme. + /// + /// An array of bytes that has to be sent if the user wants to authenticate with the username/password authentication scheme. + private byte[] GetAuthenticationBytes() { + byte[] buffer = new byte[3 + Username.Length + Password.Length]; + buffer[0] = 1; + buffer[1] = (byte)Username.Length; + Array.Copy(Encoding.ASCII.GetBytes(Username), 0, buffer, 2, Username.Length); + buffer[Username.Length + 2] = (byte)Password.Length; + Array.Copy(Encoding.ASCII.GetBytes(Password), 0, buffer, Username.Length + 3, Password.Length); + return buffer; + } + /// + /// Starts the authentication process. + /// + public override void Authenticate() { + Server.Send(GetAuthenticationBytes()); + byte[] buffer = new byte[2]; + int received = 0; + while (received != 2) { + received += Server.Receive(buffer, received, 2 - received, SocketFlags.None); + } + if (buffer[1] != 0) { + Server.Close(); + throw new ProxyException("Username/password combination rejected."); + } + return; + } + /// + /// Starts the asynchronous authentication process. + /// + /// The method to call when the authentication is complete. + public override void BeginAuthenticate(HandShakeComplete callback) { + CallBack = callback; + Server.BeginSend(GetAuthenticationBytes(), 0, 3 + Username.Length + Password.Length, SocketFlags.None, new AsyncCallback(this.OnSent), Server); + return; + } + /// + /// Called when the authentication bytes have been sent. + /// + /// Stores state information for this asynchronous operation as well as any user-defined data. + private void OnSent(IAsyncResult ar) { + try { + Server.EndSend(ar); + Buffer = new byte[2]; + Server.BeginReceive(Buffer, 0, 2, SocketFlags.None, new AsyncCallback(this.OnReceive), Server); + } catch (Exception e) { + CallBack(e); + } + } + /// + /// Called when the socket received an authentication reply. + /// + /// Stores state information for this asynchronous operation as well as any user-defined data. + private void OnReceive(IAsyncResult ar) { + try { + Received += Server.EndReceive(ar); + if (Received == Buffer.Length) + if (Buffer[1] == 0) + CallBack(null); + else + throw new ProxyException("Username/password combination not accepted."); + else + Server.BeginReceive(Buffer, Received, Buffer.Length - Received, SocketFlags.None, new AsyncCallback(this.OnReceive), Server); + } catch (Exception e) { + CallBack(e); + } + } + /// + /// Gets or sets the username to use when authenticating with the proxy server. + /// + /// The username to use when authenticating with the proxy server. + /// The specified value is null. + private string Username { + get { + return m_Username; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_Username = value; + } + } + /// + /// Gets or sets the password to use when authenticating with the proxy server. + /// + /// The password to use when authenticating with the proxy server. + /// The specified value is null. + private string Password { + get { + return m_Password; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_Password = value; + } + } + // private variables + /// Holds the value of the Username property. + private string m_Username; + /// Holds the value of the Password property. + private string m_Password; + } +} \ No newline at end of file diff --git a/MSNPSharp/ProxySocket/IAsyncProxyResult.cs b/MSNPSharp/ProxySocket/IAsyncProxyResult.cs new file mode 100644 index 0000000..f223486 --- /dev/null +++ b/MSNPSharp/ProxySocket/IAsyncProxyResult.cs @@ -0,0 +1,96 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Threading; + +namespace Org.Mentalis.Network.ProxySocket { + /// + /// A class that implements the IAsyncResult interface. Objects from this class are returned by the BeginConnect method of the ProxySocket class. + /// + internal class IAsyncProxyResult : IAsyncResult { + /// Initializes the internal variables of this object + /// An object that contains state information for this request. + internal void Init(object stateObject) { + m_StateObject = stateObject; + m_Completed = false; + if (m_WaitHandle != null) + m_WaitHandle.Reset(); + + } + /// Initializes the internal variables of this object + internal void Reset() { + m_StateObject = null; + m_Completed = true; + if (m_WaitHandle != null) + m_WaitHandle.Set(); + } + /// Gets a value that indicates whether the server has completed processing the call. It is illegal for the server to use any client supplied resources outside of the agreed upon sharing semantics after it sets the IsCompleted property to "true". Thus, it is safe for the client to destroy the resources after IsCompleted property returns "true". + /// A boolean that indicates whether the server has completed processing the call. + public bool IsCompleted { + get { + return m_Completed; + } + } + /// Gets a value that indicates whether the BeginXXXX call has been completed synchronously. If this is detected in the AsyncCallback delegate, it is probable that the thread that called BeginInvoke is the current thread. + /// Returns false. + public bool CompletedSynchronously { + get { + return false; + } + } + /// Gets an object that was passed as the state parameter of the BeginXXXX method call. + /// The object that was passed as the state parameter of the BeginXXXX method call. + public object AsyncState { + get { + return m_StateObject; + } + } + /// + /// The AsyncWaitHandle property returns the WaitHandle that can use to perform a WaitHandle.WaitOne or WaitAny or WaitAll. The object which implements IAsyncResult need not derive from the System.WaitHandle classes directly. The WaitHandle wraps its underlying synchronization primitive and should be signaled after the call is completed. This enables the client to wait for the call to complete instead polling. The Runtime supplies a number of waitable objects that mirror Win32 synchronization primitives e.g. ManualResetEvent, AutoResetEvent and Mutex. + /// WaitHandle supplies methods that support waiting for such synchronization objects to become signaled with "any" or "all" semantics i.e. WaitHandle.WaitOne, WaitAny and WaitAll. Such methods are context aware to avoid deadlocks. The AsyncWaitHandle can be allocated eagerly or on demand. It is the choice of the IAsyncResult implementer. + /// + /// The WaitHandle associated with this asynchronous result. + public WaitHandle AsyncWaitHandle { + get { + if (m_WaitHandle == null) + m_WaitHandle = new ManualResetEvent(false); + return m_WaitHandle; + } + } + // private variables + /// Used internally to represent the state of the asynchronous request + internal bool m_Completed = true; + /// Holds the value of the StateObject property. + private object m_StateObject; + /// Holds the value of the WaitHandle property. + private ManualResetEvent m_WaitHandle; + } +} \ No newline at end of file diff --git a/MSNPSharp/ProxySocket/ProxyException.cs b/MSNPSharp/ProxySocket/ProxyException.cs new file mode 100644 index 0000000..235b700 --- /dev/null +++ b/MSNPSharp/ProxySocket/ProxyException.cs @@ -0,0 +1,82 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; + +namespace Org.Mentalis.Network.ProxySocket { + /// + /// The exception that is thrown when a proxy error occurs. + /// + public class ProxyException : Exception { + /// + /// Initializes a new instance of the ProxyException class. + /// + public ProxyException() : this("An error Occurred while talking to the proxy server.") {} + /// + /// Initializes a new instance of the ProxyException class. + /// + /// The message that describes the error. + public ProxyException(string message) : base(message) {} + /// + /// Initializes a new instance of the ProxyException class. + /// + /// The error number returned by a SOCKS5 server. + public ProxyException(int socks5Error) : this(ProxyException.Socks5ToString(socks5Error)) {} + /// + /// Converts a SOCKS5 error number to a human readable string. + /// + /// The error number returned by a SOCKS5 server. + /// A string representation of the specified SOCKS5 error number. + public static string Socks5ToString(int socks5Error) { + switch(socks5Error) { + case 0: + return "Connection succeeded."; + case 1: + return "General SOCKS server failure."; + case 2: + return "Connection not allowed by ruleset."; + case 3: + return "Network unreachable."; + case 4: + return "Host unreachable."; + case 5: + return "Connection refused."; + case 6: + return "TTL expired."; + case 7: + return "Command not supported."; + case 8: + return "Address type not supported."; + default: + return "Unspecified SOCKS error."; + } + } + } +} \ No newline at end of file diff --git a/MSNPSharp/ProxySocket/ProxySocket.cs b/MSNPSharp/ProxySocket/ProxySocket.cs new file mode 100644 index 0000000..8f4f84b --- /dev/null +++ b/MSNPSharp/ProxySocket/ProxySocket.cs @@ -0,0 +1,389 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; + +// Implements a number of classes to allow Sockets to connect trough a firewall. +namespace Org.Mentalis.Network.ProxySocket { + /// + /// Specifies the type of proxy servers that an instance of the ProxySocket class can use. + /// + public enum ProxyTypes { + /// No proxy server; the ProxySocket object behaves exactly like an ordinary Socket object. + None, + /// A SOCKS4[A] proxy server. + Socks4, + /// A SOCKS5 proxy server. + Socks5 + } + /// + /// Implements a Socket class that can connect trough a SOCKS proxy server. + /// + /// This class implements SOCKS4[A] and SOCKS5.
It does not, however, implement the BIND commands, so you cannot .
+ public class ProxySocket : Socket { + /// + /// Initializes a new instance of the ProxySocket class. + /// + /// One of the AddressFamily values. + /// One of the SocketType values. + /// One of the ProtocolType values. + /// The combination of addressFamily, socketType, and protocolType results in an invalid socket. + public ProxySocket (AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) : this(addressFamily, socketType, protocolType, "") {} + /// + /// Initializes a new instance of the ProxySocket class. + /// + /// One of the AddressFamily values. + /// One of the SocketType values. + /// One of the ProtocolType values. + /// The username to use when authenticating with the proxy server. + /// The combination of addressFamily, socketType, and protocolType results in an invalid socket. + /// proxyUsername is null. + public ProxySocket (AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, string proxyUsername) : this(addressFamily, socketType, protocolType, proxyUsername, "") {} + /// + /// Initializes a new instance of the ProxySocket class. + /// + /// One of the AddressFamily values. + /// One of the SocketType values. + /// One of the ProtocolType values. + /// The username to use when authenticating with the proxy server. + /// The password to use when authenticating with the proxy server. + /// The combination of addressFamily, socketType, and protocolType results in an invalid socket. + /// proxyUsername -or- proxyPassword is null. + public ProxySocket (AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, string proxyUsername, string proxyPassword) : base(addressFamily, socketType, protocolType) { + ProxyUser = proxyUsername; + ProxyPass = proxyPassword; + ToThrow = new InvalidOperationException(); + } + /// + /// Establishes a connection to a remote device. + /// + /// An EndPoint that represents the remote device. + /// The remoteEP parameter is a null reference (Nothing in Visual Basic). + /// An operating system error occurs while accessing the Socket. + /// The Socket has been closed. + /// An error Occurred while talking to the proxy server. + public new void Connect(EndPoint remoteEP) { + if (remoteEP == null) + throw new ArgumentNullException(" cannot be null."); + if (this.ProtocolType != ProtocolType.Tcp || ProxyType == ProxyTypes.None || ProxyEndPoint == null) + base.Connect(remoteEP); + else { + base.Connect(ProxyEndPoint); + if (ProxyType == ProxyTypes.Socks4) + (new Socks4Handler(this, ProxyUser)).Negotiate((IPEndPoint)remoteEP); + else if (ProxyType == ProxyTypes.Socks5) + (new Socks5Handler(this, ProxyUser, ProxyPass)).Negotiate((IPEndPoint)remoteEP); + } + } + /// + /// Establishes a connection to a remote device. + /// + /// The remote host to connect to. + /// The remote port to connect to. + /// The host parameter is a null reference (Nothing in Visual Basic). + /// The port parameter is invalid. + /// An operating system error occurs while accessing the Socket. + /// The Socket has been closed. + /// An error Occurred while talking to the proxy server. + /// If you use this method with a SOCKS4 server, it will let the server resolve the hostname. Not all SOCKS4 servers support this 'remote DNS' though. + new public void Connect(string host, int port) { + if (host == null) + throw new ArgumentNullException(" cannot be null."); + if (port <= 0 || port > 65535) + throw new ArgumentException("Invalid port."); + if (this.ProtocolType != ProtocolType.Tcp || ProxyType == ProxyTypes.None || ProxyEndPoint == null) + base.Connect(new IPEndPoint(Dns.GetHostEntry(host).AddressList[0], port)); + else { + base.Connect(ProxyEndPoint); + if (ProxyType == ProxyTypes.Socks4) + (new Socks4Handler(this, ProxyUser)).Negotiate(host, port); + else if (ProxyType == ProxyTypes.Socks5) + (new Socks5Handler(this, ProxyUser, ProxyPass)).Negotiate(host, port); + } + } + /// + /// Begins an asynchronous request for a connection to a network device. + /// + /// An EndPoint that represents the remote device. + /// The AsyncCallback delegate. + /// An object that contains state information for this request. + /// An IAsyncResult that references the asynchronous connection. + /// The remoteEP parameter is a null reference (Nothing in Visual Basic). + /// An operating system error occurs while creating the Socket. + /// The Socket has been closed. + public new IAsyncResult BeginConnect(EndPoint remoteEP, AsyncCallback callback, object state) { + if (remoteEP == null || callback == null) + throw new ArgumentNullException(); + + if (this.ProtocolType != ProtocolType.Tcp || ProxyType == ProxyTypes.None || ProxyEndPoint == null) { + ToThrow = null; + return base.BeginConnect(remoteEP, callback, state); + } else { + CallBack = callback; + if (ProxyType == ProxyTypes.Socks4) { + AsyncResult = (new Socks4Handler(this, ProxyUser)).BeginNegotiate((IPEndPoint)remoteEP, new HandShakeComplete(this.OnHandShakeComplete), ProxyEndPoint); + return AsyncResult; + } else if(ProxyType == ProxyTypes.Socks5) { + AsyncResult = (new Socks5Handler(this, ProxyUser, ProxyPass)).BeginNegotiate((IPEndPoint)remoteEP, new HandShakeComplete(this.OnHandShakeComplete), ProxyEndPoint); + return AsyncResult; + } + return null; + } + } + /// + /// Begins an asynchronous request for a connection to a network device. + /// + /// The host to connect to. + /// The port on the remote host to connect to. + /// The AsyncCallback delegate. + /// An object that contains state information for this request. + /// An IAsyncResult that references the asynchronous connection. + /// The host parameter is a null reference (Nothing in Visual Basic). + /// The port parameter is invalid. + /// An operating system error occurs while creating the Socket. + /// The Socket has been closed. + new public IAsyncResult BeginConnect(string host, int port, AsyncCallback callback, object state) { + if (host == null || callback == null) + throw new ArgumentNullException(); + if (port <= 0 || port > 65535) + throw new ArgumentException(); + CallBack = callback; + //State = state; + if (this.ProtocolType != ProtocolType.Tcp || ProxyType == ProxyTypes.None || ProxyEndPoint == null) { + RemotePort = port; + AsyncResult = BeginDns(host, new HandShakeComplete(this.OnHandShakeComplete)); + return AsyncResult; + } else { + if (ProxyType == ProxyTypes.Socks4) { + AsyncResult = (new Socks4Handler(this, ProxyUser)).BeginNegotiate(host, port, new HandShakeComplete(this.OnHandShakeComplete), ProxyEndPoint); + return AsyncResult; + } else if(ProxyType == ProxyTypes.Socks5) { + AsyncResult = (new Socks5Handler(this, ProxyUser, ProxyPass)).BeginNegotiate(host, port, new HandShakeComplete(this.OnHandShakeComplete), ProxyEndPoint); + return AsyncResult; + } + return null; + } + } + + /// + /// Ends a pending asynchronous connection request. + /// + /// Stores state information for this asynchronous operation as well as any user-defined data. + /// The asyncResult parameter is a null reference (Nothing in Visual Basic). + /// The asyncResult parameter was not returned by a call to the BeginConnect method. + /// An operating system error occurs while accessing the Socket. + /// The Socket has been closed. + /// EndConnect was previously called for the asynchronous connection. + /// The proxy server refused the connection. + public new void EndConnect(IAsyncResult asyncResult) { + if (asyncResult == null) + throw new ArgumentNullException(); + if (!asyncResult.IsCompleted) + throw new ArgumentException(); + if (ToThrow != null) + throw ToThrow; + return; + } + /// + /// Begins an asynchronous request to resolve a DNS host name or IP address in dotted-quad notation to an IPAddress instance. + /// + /// The host to resolve. + /// The method to call when the hostname has been resolved. + /// An IAsyncResult instance that references the asynchronous request. + /// There was an error while trying to resolve the host. + internal IAsyncProxyResult BeginDns(string host, HandShakeComplete callback) { + try { + Dns.BeginGetHostEntry(host, new AsyncCallback(this.OnResolved), this); + return new IAsyncProxyResult(); + } catch { + throw new SocketException(); + } + } + /// + /// Called when the specified hostname has been resolved. + /// + /// The result of the asynchronous operation. + private void OnResolved(IAsyncResult asyncResult) { + try { + IPHostEntry dns = Dns.EndGetHostEntry(asyncResult); + base.BeginConnect(new IPEndPoint(dns.AddressList[0], RemotePort), new AsyncCallback(this.OnConnect), State); + } catch (Exception e) { + OnHandShakeComplete(e); + } + } + /// + /// Called when the Socket is connected to the remote host. + /// + /// The result of the asynchronous operation. + private void OnConnect(IAsyncResult asyncResult) { + try { + base.EndConnect(asyncResult); + OnHandShakeComplete(null); + } catch (Exception e) { + OnHandShakeComplete(e); + } + } + /// + /// Called when the Socket has finished talking to the proxy server and is ready to relay data. + /// + /// The error to throw when the EndConnect method is called. + private void OnHandShakeComplete(Exception error) { + if (error != null) + this.Close(); + ToThrow = error; + AsyncResult.Reset(); + if (CallBack != null) + CallBack(AsyncResult); + } + /// + /// Gets or sets the EndPoint of the proxy server. + /// + /// An IPEndPoint object that holds the IP address and the port of the proxy server. + public IPEndPoint ProxyEndPoint { + get { + return m_ProxyEndPoint; + } + set { + m_ProxyEndPoint = value; + } + } + /// + /// Gets or sets the type of proxy server to use. + /// + /// One of the ProxyTypes values. + public ProxyTypes ProxyType { + get { + return m_ProxyType; + } + set { + m_ProxyType = value; + } + } + /// + /// Gets or sets a user-defined object. + /// + /// The user-defined object. + private object State { + get { + return m_State; + } + set { + m_State = value; + } + } + /// + /// Gets or sets the username to use when authenticating with the proxy. + /// + /// A string that holds the username that's used when authenticating with the proxy. + /// The specified value is null. + public string ProxyUser { + get { + return m_ProxyUser; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_ProxyUser = value; + } + } + /// + /// Gets or sets the password to use when authenticating with the proxy. + /// + /// A string that holds the password that's used when authenticating with the proxy. + /// The specified value is null. + public string ProxyPass { + get { + return m_ProxyPass; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_ProxyPass = value; + } + } + /// + /// Gets or sets the asynchronous result object. + /// + /// An instance of the IAsyncProxyResult class. + private IAsyncProxyResult AsyncResult { + get { + return m_AsyncResult; + } + set { + m_AsyncResult = value; + } + } + /// + /// Gets or sets the exception to throw when the EndConnect method is called. + /// + /// An instance of the Exception class (or subclasses of Exception). + private Exception ToThrow { + get { + return m_ToThrow; + } + set { + m_ToThrow = value; + } + } + /// + /// Gets or sets the remote port the user wants to connect to. + /// + /// An integer that specifies the port the user wants to connect to. + private int RemotePort { + get { + return m_RemotePort; + } + set { + m_RemotePort = value; + } + } + // private variables + /// Holds the value of the State property. + private object m_State; + /// Holds the value of the ProxyEndPoint property. + private IPEndPoint m_ProxyEndPoint = null; + /// Holds the value of the ProxyType property. + private ProxyTypes m_ProxyType = ProxyTypes.None; + /// Holds the value of the ProxyUser property. + private string m_ProxyUser = null; + /// Holds the value of the ProxyPass property. + private string m_ProxyPass = null; + /// Holds a pointer to the method that should be called when the Socket is connected to the remote device. + private AsyncCallback CallBack = null; + /// Holds the value of the AsyncResult property. + private IAsyncProxyResult m_AsyncResult; + /// Holds the value of the ToThrow property. + private Exception m_ToThrow = null; + /// Holds the value of the RemotePort property. + private int m_RemotePort; + } +} \ No newline at end of file diff --git a/MSNPSharp/ProxySocket/Socks4Handler.cs b/MSNPSharp/ProxySocket/Socks4Handler.cs new file mode 100644 index 0000000..924721b --- /dev/null +++ b/MSNPSharp/ProxySocket/Socks4Handler.cs @@ -0,0 +1,234 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; + +namespace Org.Mentalis.Network.ProxySocket { + /// + /// Implements the SOCKS4[A] protocol. + /// + internal sealed class Socks4Handler : SocksHandler { + /// + /// Initilizes a new instance of the SocksHandler class. + /// + /// The socket connection with the proxy server. + /// The username to use when authenticating with the server. + /// server -or- user is null. + public Socks4Handler(Socket server, string user) : base(server, user) {} + /// + /// Creates an array of bytes that has to be sent when the user wants to connect to a specific host/port combination. + /// + /// The host to connect to. + /// The port to connect to. + /// An array of bytes that has to be sent when the user wants to connect to a specific host/port combination. + /// Resolving the host name will be done at server side. Do note that some SOCKS4 servers do not implement this functionality. + /// host is null. + /// port is invalid. + private byte[] GetHostPortBytes(string host, int port) { + if (host == null) + throw new ArgumentNullException(); + if (port <= 0 || port > 65535) + throw new ArgumentException(); + byte [] connect = new byte[10 + Username.Length + host.Length]; + connect[0] = 4; + connect[1] = 1; + Array.Copy(PortToBytes(port), 0, connect, 2, 2); + connect[4] = connect[5] = connect[6] = 0; + connect[7] = 1; + Array.Copy(Encoding.ASCII.GetBytes(Username), 0, connect, 8, Username.Length); + connect[8 + Username.Length] = 0; + Array.Copy(Encoding.ASCII.GetBytes(host), 0, connect, 9 + Username.Length, host.Length); + connect[9 + Username.Length + host.Length] = 0; + return connect; + } + /// + /// Creates an array of bytes that has to be sent when the user wants to connect to a specific IPEndPoint. + /// + /// The IPEndPoint to connect to. + /// An array of bytes that has to be sent when the user wants to connect to a specific IPEndPoint. + /// remoteEP is null. + private byte[] GetEndPointBytes(IPEndPoint remoteEP) { + if (remoteEP == null) + throw new ArgumentNullException(); + byte [] connect = new byte[9 + Username.Length]; + connect[0] = 4; + connect[1] = 1; + Array.Copy(PortToBytes(remoteEP.Port), 0, connect, 2, 2); + Array.Copy(remoteEP.Address.GetAddressBytes(), 0, connect, 4, 4); + Array.Copy(Encoding.ASCII.GetBytes(Username), 0, connect, 8, Username.Length); + connect[8 + Username.Length] = 0; + return connect; + } + /// + /// Starts negotiating with the SOCKS server. + /// + /// The host to connect to. + /// The port to connect to. + /// host is null. + /// port is invalid. + /// The proxy rejected the request. + /// An operating system error occurs while accessing the Socket. + /// The Socket has been closed. + public override void Negotiate(string host, int port) { + Negotiate(GetHostPortBytes(host, port)); + } + /// + /// Starts negotiating with the SOCKS server. + /// + /// The IPEndPoint to connect to. + /// remoteEP is null. + /// The proxy rejected the request. + /// An operating system error occurs while accessing the Socket. + /// The Socket has been closed. + public override void Negotiate(IPEndPoint remoteEP) { + Negotiate(GetEndPointBytes(remoteEP)); + } + /// + /// Starts negotiating with the SOCKS server. + /// + /// The bytes to send when trying to authenticate. + /// connect is null. + /// connect is too small. + /// The proxy rejected the request. + /// An operating system error occurs while accessing the Socket. + /// The Socket has been closed. + private void Negotiate(byte [] connect) { + if (connect == null) + throw new ArgumentNullException(); + if (connect.Length < 2) + throw new ArgumentException(); + Server.Send(connect); + byte [] buffer = ReadBytes(8); + if (buffer[1] != 90) { + Server.Close(); + throw new ProxyException("Negotiation failed."); + } + } + /// + /// Starts negotiating asynchronously with a SOCKS proxy server. + /// + /// The remote server to connect to. + /// The remote port to connect to. + /// The method to call when the connection has been established. + /// The IPEndPoint of the SOCKS proxy server. + /// An IAsyncProxyResult that references the asynchronous connection. + public override IAsyncProxyResult BeginNegotiate(string host, int port, HandShakeComplete callback, IPEndPoint proxyEndPoint) { + ProtocolComplete = callback; + Buffer = GetHostPortBytes(host, port); + Server.BeginConnect(proxyEndPoint, new AsyncCallback(this.OnConnect), Server); + AsyncResult = new IAsyncProxyResult(); + return AsyncResult; + } + /// + /// Starts negotiating asynchronously with a SOCKS proxy server. + /// + /// An IPEndPoint that represents the remote device. + /// The method to call when the connection has been established. + /// The IPEndPoint of the SOCKS proxy server. + /// An IAsyncProxyResult that references the asynchronous connection. + public override IAsyncProxyResult BeginNegotiate(IPEndPoint remoteEP, HandShakeComplete callback, IPEndPoint proxyEndPoint) { + ProtocolComplete = callback; + Buffer = GetEndPointBytes(remoteEP); + Server.BeginConnect(proxyEndPoint, new AsyncCallback(this.OnConnect), Server); + AsyncResult = new IAsyncProxyResult(); + return AsyncResult; + } + /// + /// Called when the Socket is connected to the remote proxy server. + /// + /// Stores state information for this asynchronous operation as well as any user-defined data. + private void OnConnect(IAsyncResult ar) { + try { + Server.EndConnect(ar); + } catch (Exception e) { + ProtocolComplete(e); + return; + } + try { + Server.BeginSend(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnSent), Server); + } catch (Exception e) { + ProtocolComplete(e); + } + } + /// + /// Called when the Socket has sent the handshake data. + /// + /// Stores state information for this asynchronous operation as well as any user-defined data. + private void OnSent(IAsyncResult ar) { + try { + if (Server.EndSend(ar) < Buffer.Length) { + ProtocolComplete(new SocketException()); + return; + } + } catch (Exception e) { + ProtocolComplete(e); + return; + } + try { + Buffer = new byte[8]; + Received = 0; + Server.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceive), Server); + } catch (Exception e) { + ProtocolComplete(e); + } + } + /// + /// Called when the Socket has received a reply from the remote proxy server. + /// + /// Stores state information for this asynchronous operation as well as any user-defined data. + private void OnReceive(IAsyncResult ar) { + try { + int received = Server.EndReceive(ar); + if (received <= 0) { + ProtocolComplete(new SocketException()); + return; + } + Received += received; + if (Received == 8) { + if (Buffer[1] == 90) + ProtocolComplete(null); + else { + Server.Close(); + ProtocolComplete(new ProxyException("Negotiation failed.")); + } + } else { + Server.BeginReceive(Buffer, Received, Buffer.Length - Received, SocketFlags.None, new AsyncCallback(this.OnReceive), Server); + } + } catch (Exception e) { + ProtocolComplete(e); + } + } + } +} + + diff --git a/MSNPSharp/ProxySocket/Socks5Handler.cs b/MSNPSharp/ProxySocket/Socks5Handler.cs new file mode 100644 index 0000000..b9ac4fd --- /dev/null +++ b/MSNPSharp/ProxySocket/Socks5Handler.cs @@ -0,0 +1,419 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; +using Org.Mentalis.Network.ProxySocket.Authentication; + +namespace Org.Mentalis.Network.ProxySocket { + /// + /// Implements the SOCKS5 protocol. + /// + internal sealed class Socks5Handler : SocksHandler { + /// + /// Initiliazes a new Socks5Handler instance. + /// + /// The socket connection with the proxy server. + /// server is null. + public Socks5Handler(Socket server) : this(server, "") {} + /// + /// Initiliazes a new Socks5Handler instance. + /// + /// The socket connection with the proxy server. + /// The username to use. + /// server -or- user is null. + public Socks5Handler(Socket server, string user) : this(server, user, "") {} + /// + /// Initiliazes a new Socks5Handler instance. + /// + /// The socket connection with the proxy server. + /// The username to use. + /// The password to use. + /// server -or- user -or- pass is null. + public Socks5Handler(Socket server, string user, string pass) : base(server, user) { + Password = pass; + } + /// + /// Starts the synchronous authentication process. + /// + /// Authentication with the proxy server failed. + /// The proxy server uses an invalid protocol. + /// An operating system error occurs while accessing the Socket. + /// The Socket has been closed. + private void Authenticate() { + Server.Send(new byte [] {5, 2, 0, 2}); + byte[] buffer = ReadBytes(2); + if (buffer[1] == 255) + throw new ProxyException("No authentication method accepted."); + AuthMethod authenticate; + switch (buffer[1]) { + case 0: + authenticate = new AuthNone(Server); + break; + case 2: + authenticate = new AuthUserPass(Server, Username, Password); + break; + default: + throw new ProtocolViolationException(); + } + authenticate.Authenticate(); + } + /// + /// Creates an array of bytes that has to be sent when the user wants to connect to a specific host/port combination. + /// + /// The host to connect to. + /// The port to connect to. + /// An array of bytes that has to be sent when the user wants to connect to a specific host/port combination. + /// host is null. + /// port or host is invalid. + private byte[] GetHostPortBytes(string host, int port) { + if (host == null) + throw new ArgumentNullException(); + if (port <= 0 || port > 65535 || host.Length > 255) + throw new ArgumentException(); + byte [] connect = new byte[7 + host.Length]; + connect[0] = 5; + connect[1] = 1; + connect[2] = 0; //reserved + connect[3] = 3; + connect[4] = (byte)host.Length; + Array.Copy(Encoding.ASCII.GetBytes(host), 0, connect, 5, host.Length); + Array.Copy(PortToBytes(port), 0, connect, host.Length + 5, 2); + return connect; + } + /// + /// Creates an array of bytes that has to be sent when the user wants to connect to a specific IPEndPoint. + /// + /// The IPEndPoint to connect to. + /// An array of bytes that has to be sent when the user wants to connect to a specific IPEndPoint. + /// remoteEP is null. + private byte[] GetEndPointBytes(IPEndPoint remoteEP) { + if (remoteEP == null) + throw new ArgumentNullException(); + byte [] connect = new byte[10]; + connect[0] = 5; + connect[1] = 1; + connect[2] = 0; //reserved + connect[3] = 1; + Array.Copy(remoteEP.Address.GetAddressBytes(), 0, connect, 4, 4); + Array.Copy(PortToBytes(remoteEP.Port), 0, connect, 8, 2); + return connect; + } + /// + /// Starts negotiating with the SOCKS server. + /// + /// The host to connect to. + /// The port to connect to. + /// host is null. + /// port is invalid. + /// The proxy rejected the request. + /// An operating system error occurs while accessing the Socket. + /// The Socket has been closed. + /// The proxy server uses an invalid protocol. + public override void Negotiate(string host, int port) { + Negotiate(GetHostPortBytes(host, port)); + } + /// + /// Starts negotiating with the SOCKS server. + /// + /// The IPEndPoint to connect to. + /// remoteEP is null. + /// The proxy rejected the request. + /// An operating system error occurs while accessing the Socket. + /// The Socket has been closed. + /// The proxy server uses an invalid protocol. + public override void Negotiate(IPEndPoint remoteEP) { + Negotiate(GetEndPointBytes(remoteEP)); + } + /// + /// Starts negotiating with the SOCKS server. + /// + /// The bytes to send when trying to authenticate. + /// connect is null. + /// connect is too small. + /// The proxy rejected the request. + /// An operating system error occurs while accessing the Socket. + /// The Socket has been closed. + /// The proxy server uses an invalid protocol. + private void Negotiate(byte[] connect) { + Authenticate(); + Server.Send(connect); + byte[] buffer = ReadBytes(4); + if (buffer[1] != 0) { + Server.Close(); + throw new ProxyException(buffer[1]); + } + switch(buffer[3]) { + case 1: + buffer = ReadBytes(6); //IPv4 address with port + break; + case 3: + buffer = ReadBytes(1); + buffer = ReadBytes(buffer[0] + 2); //domain name with port + break; + case 4: + buffer = ReadBytes(18); //IPv6 address with port + break; + default: + Server.Close(); + throw new ProtocolViolationException(); + } + } + /// + /// Starts negotiating asynchronously with the SOCKS server. + /// + /// The host to connect to. + /// The port to connect to. + /// The method to call when the negotiation is complete. + /// The IPEndPoint of the SOCKS proxy server. + /// An IAsyncProxyResult that references the asynchronous connection. + public override IAsyncProxyResult BeginNegotiate(string host, int port, HandShakeComplete callback, IPEndPoint proxyEndPoint) { + ProtocolComplete = callback; + HandShake = GetHostPortBytes(host, port); + Server.BeginConnect(proxyEndPoint, new AsyncCallback(this.OnConnect), Server); + AsyncResult = new IAsyncProxyResult(); + return AsyncResult; + } + /// + /// Starts negotiating asynchronously with the SOCKS server. + /// + /// An IPEndPoint that represents the remote device. + /// The method to call when the negotiation is complete. + /// The IPEndPoint of the SOCKS proxy server. + /// An IAsyncProxyResult that references the asynchronous connection. + public override IAsyncProxyResult BeginNegotiate(IPEndPoint remoteEP, HandShakeComplete callback, IPEndPoint proxyEndPoint) { + ProtocolComplete = callback; + HandShake = GetEndPointBytes(remoteEP); + Server.BeginConnect(proxyEndPoint, new AsyncCallback(this.OnConnect), Server); + AsyncResult = new IAsyncProxyResult(); + return AsyncResult; + } + /// + /// Called when the socket is connected to the remote server. + /// + /// Stores state information for this asynchronous operation as well as any user-defined data. + private void OnConnect(IAsyncResult ar) { + try { + Server.EndConnect(ar); + } catch (Exception e) { + ProtocolComplete(e); + return; + } + try { + Server.BeginSend(new byte [] {5, 2, 0, 2}, 0, 4, SocketFlags.None, new AsyncCallback(this.OnAuthSent), Server); + } catch (Exception e) { + ProtocolComplete(e); + } + } + /// + /// Called when the authentication bytes have been sent. + /// + /// Stores state information for this asynchronous operation as well as any user-defined data. + private void OnAuthSent(IAsyncResult ar) { + try { + Server.EndSend(ar); + } catch (Exception e) { + ProtocolComplete(e); + return; + } + try { + Buffer = new byte[1024]; + Received = 0; + Server.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnAuthReceive), Server); + } catch (Exception e) { + ProtocolComplete(e); + } + } + /// + /// Called when an authentication reply has been received. + /// + /// Stores state information for this asynchronous operation as well as any user-defined data. + private void OnAuthReceive(IAsyncResult ar) { + try { + Received += Server.EndReceive(ar); + if (Received <= 0) + throw new SocketException(); + } catch (Exception e) { + ProtocolComplete(e); + return; + } + try { + if (Received < 2) { + Server.BeginReceive(Buffer, Received, Buffer.Length - Received, SocketFlags.None, new AsyncCallback(this.OnAuthReceive), Server); + } else { + AuthMethod authenticate; + switch(Buffer[1]) { + case 0: + authenticate = new AuthNone(Server); + break; + case 2: + authenticate = new AuthUserPass(Server, Username, Password); + break; + default: + ProtocolComplete(new SocketException()); + return; + } + authenticate.BeginAuthenticate(new HandShakeComplete(this.OnAuthenticated)); + } + } catch (Exception e) { + ProtocolComplete(e); + } + } + /// + /// Called when the socket has been successfully authenticated with the server. + /// + /// The exception that has Occurred while authenticating, or null if no error Occurred. + private void OnAuthenticated(Exception e) { + if (e != null) { + ProtocolComplete(e); + return; + } + try { + Server.BeginSend(HandShake, 0, HandShake.Length, SocketFlags.None, new AsyncCallback(this.OnSent), Server); + } catch (Exception ex) { + ProtocolComplete(ex); + } + } + /// + /// Called when the connection request has been sent. + /// + /// Stores state information for this asynchronous operation as well as any user-defined data. + private void OnSent(IAsyncResult ar) { + try { + Server.EndSend(ar); + } catch (Exception e) { + ProtocolComplete(e); + return; + } + try { + Buffer = new byte[5]; + Received = 0; + Server.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceive), Server); + } catch (Exception e) { + ProtocolComplete(e); + } + } + /// + /// Called when a connection reply has been received. + /// + /// Stores state information for this asynchronous operation as well as any user-defined data. + private void OnReceive(IAsyncResult ar) { + try { + Received += Server.EndReceive(ar); + } catch (Exception e) { + ProtocolComplete(e); + return; + } + try { + if (Received == Buffer.Length) + ProcessReply(Buffer); + else + Server.BeginReceive(Buffer, Received, Buffer.Length - Received, SocketFlags.None, new AsyncCallback(this.OnReceive), Server); + } catch (Exception e) { + ProtocolComplete(e); + } + } + /// + /// Processes the received reply. + /// + /// The received reply + /// The received reply is invalid. + private void ProcessReply(byte[] buffer) { + switch(buffer[3]) { + case 1: + Buffer = new byte[5]; //IPv4 address with port - 1 byte + break; + case 3: + Buffer = new byte[buffer[4] + 2]; //domain name with port + break; + case 4: + buffer = new byte[17]; //IPv6 address with port - 1 byte + break; + default: + throw new ProtocolViolationException(); + } + Received = 0; + Server.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReadLast), Server); + } + /// + /// Called when the last bytes are read from the socket. + /// + /// Stores state information for this asynchronous operation as well as any user-defined data. + private void OnReadLast(IAsyncResult ar) { + try { + Received += Server.EndReceive(ar); + } catch (Exception e) { + ProtocolComplete(e); + return; + } + try { + if (Received == Buffer.Length) + ProtocolComplete(null); + else + Server.BeginReceive(Buffer, Received, Buffer.Length - Received, SocketFlags.None, new AsyncCallback(this.OnReadLast), Server); + } catch (Exception e) { + ProtocolComplete(e); + } + } + /// + /// Gets or sets the password to use when authenticating with the SOCKS5 server. + /// + /// The password to use when authenticating with the SOCKS5 server. + private string Password { + get { + return m_Password; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_Password = value; + } + } + /// + /// Gets or sets the bytes to use when sending a connect request to the proxy server. + /// + /// The array of bytes to use when sending a connect request to the proxy server. + private byte[] HandShake { + get { + return m_HandShake; + } + set { + m_HandShake = value; + } + } + // private variables + /// Holds the value of the Password property. + private string m_Password; + /// Holds the value of the HandShake property. + private byte[] m_HandShake; + } +} \ No newline at end of file diff --git a/MSNPSharp/ProxySocket/SocksHandler.cs b/MSNPSharp/ProxySocket/SocksHandler.cs new file mode 100644 index 0000000..f4ccf9f --- /dev/null +++ b/MSNPSharp/ProxySocket/SocksHandler.cs @@ -0,0 +1,204 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; + +namespace Org.Mentalis.Network.ProxySocket { + /// + /// References the callback method to be called when the protocol negotiation is completed. + /// + internal delegate void HandShakeComplete(Exception error); + /// + /// Implements a specific version of the SOCKS protocol. This is an abstract class; it must be inherited. + /// + internal abstract class SocksHandler { + /// + /// Initilizes a new instance of the SocksHandler class. + /// + /// The socket connection with the proxy server. + /// The username to use when authenticating with the server. + /// server -or- user is null. + public SocksHandler(Socket server, string user) { + Server = server; + Username = user; + } + /// + /// Converts a port number to an array of bytes. + /// + /// The port to convert. + /// An array of two bytes that represents the specified port. + protected byte[] PortToBytes(int port) { + byte [] ret = new byte[2]; + ret[0] = (byte)(port / 256); + ret[1] = (byte)(port % 256); + return ret; + } + /// + /// Converts an IP address to an array of bytes. + /// + /// The IP address to convert. + /// An array of four bytes that represents the specified IP address. + protected byte[] AddressToBytes(long address) { + byte [] ret = new byte[4]; + ret[0] = (byte)(address % 256); + ret[1] = (byte)((address / 256) % 256); + ret[2] = (byte)((address / 65536) % 256); + ret[3] = (byte)(address / 16777216); + return ret; + } + /// + /// Reads a specified number of bytes from the Server socket. + /// + /// The number of bytes to return. + /// An array of bytes. + /// The number of bytes to read is invalid. + /// An operating system error occurs while accessing the Socket. + /// The Socket has been closed. + protected byte[] ReadBytes(int count) { + if (count <= 0) + throw new ArgumentException(); + byte[] buffer = new byte[count]; + int received = 0; + while(received != count) { + received += Server.Receive(buffer, received, count - received, SocketFlags.None); + } + return buffer; + } + /// + /// Gets or sets the socket connection with the proxy server. + /// + /// A Socket object that represents the connection with the proxy server. + /// The specified value is null. + protected Socket Server { + get { + return m_Server; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_Server = value; + } + } + /// + /// Gets or sets the username to use when authenticating with the proxy server. + /// + /// A string that holds the username to use when authenticating with the proxy server. + /// The specified value is null. + protected string Username { + get { + return m_Username; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_Username = value; + } + } + /// + /// Gets or sets the return value of the BeginConnect call. + /// + /// An IAsyncProxyResult object that is the return value of the BeginConnect call. + protected IAsyncProxyResult AsyncResult { + get { + return m_AsyncResult; + } + set { + m_AsyncResult = value; + } + } + /// + /// Gets or sets a byte buffer. + /// + /// An array of bytes. + protected byte[] Buffer { + get { + return m_Buffer; + } + set { + m_Buffer = value; + } + } + /// + /// Gets or sets the number of bytes that have been received from the remote proxy server. + /// + /// An integer that holds the number of bytes that have been received from the remote proxy server. + protected int Received { + get { + return m_Received; + } + set { + m_Received = value; + } + } + // private variables + /// Holds the value of the Server property. + private Socket m_Server; + /// Holds the value of the Username property. + private string m_Username; + /// Holds the value of the AsyncResult property. + private IAsyncProxyResult m_AsyncResult; + /// Holds the value of the Buffer property. + private byte[] m_Buffer; + /// Holds the value of the Received property. + private int m_Received; + /// Holds the address of the method to call when the SOCKS protocol has been completed. + protected HandShakeComplete ProtocolComplete; + /// + /// Starts negotiating with a SOCKS proxy server. + /// + /// The remote server to connect to. + /// The remote port to connect to. + public abstract void Negotiate(string host, int port); + /// + /// Starts negotiating with a SOCKS proxy server. + /// + /// The remote endpoint to connect to. + public abstract void Negotiate(IPEndPoint remoteEP); + /// + /// Starts negotiating asynchronously with a SOCKS proxy server. + /// + /// An IPEndPoint that represents the remote device. + /// The method to call when the connection has been established. + /// The IPEndPoint of the SOCKS proxy server. + /// An IAsyncProxyResult that references the asynchronous connection. + public abstract IAsyncProxyResult BeginNegotiate(IPEndPoint remoteEP, HandShakeComplete callback, IPEndPoint proxyEndPoint); + /// + /// Starts negotiating asynchronously with a SOCKS proxy server. + /// + /// The remote server to connect to. + /// The remote port to connect to. + /// The method to call when the connection has been established. + /// The IPEndPoint of the SOCKS proxy server. + /// An IAsyncProxyResult that references the asynchronous connection. + public abstract IAsyncProxyResult BeginNegotiate(string host, int port, HandShakeComplete callback, IPEndPoint proxyEndPoint); + } +} \ No newline at end of file diff --git a/MSNPSharp/QRYFactory.cs b/MSNPSharp/QRYFactory.cs new file mode 100644 index 0000000..1f5bd09 --- /dev/null +++ b/MSNPSharp/QRYFactory.cs @@ -0,0 +1,150 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +// This piece of code was written by Siebe Tolsma (Copyright 2005). +// Based on documentation by ZoRoNaX (http://zoronax.bot2k3.net/msn_beta/) +// +// This code is for eductional purposes only. Modification, use and/or publishing this code +// is entirely on your OWN risk, I can not be held responsible for any damages done by using it. +// If you have questions please contact me by posting on the BOT2K3 forum: http://bot2k3.net/forum/ + +using System; +using System.Globalization; +using System.Text; +using System.Security.Cryptography; + +namespace MSNPSharp +{ + public static class QRYFactory + { + public static string CreateQRY(string strProductID, string strProductKey, string strCHLData) + { + // First generate an MD5 hash object + MD5CryptoServiceProvider MD5 = new MD5CryptoServiceProvider(); + byte[] bMD5Bytes = Encoding.Default.GetBytes(strCHLData + strProductKey); + MD5.TransformFinalBlock(bMD5Bytes, 0, bMD5Bytes.Length); + + // Once we are done with that we should create 4 integers from the MD5 hash + string strMD5Hash = To_Hex(MD5.Hash); + ulong[] uMD5Ints = MD5_To_Int(strMD5Hash); + + // Create a new string from the ProdID and CHLData and padd with zero's, then convert it to ulongs :-) + string strCHLID = strCHLData + strProductID; + strCHLID = strCHLID.PadRight(strCHLID.Length + (8 - (strCHLID.Length % 8)), '0'); + ulong[] uCHLIDInts = CHLID_To_Int(strCHLID); + + // Then fetch the key from the two arrays + ulong uKey = Create_Key(uMD5Ints, uCHLIDInts); + + // And finally create the new hash :-) + ulong uPartOne = ulong.Parse(strMD5Hash.Substring(0, 16), NumberStyles.HexNumber); + ulong uPartTwo = ulong.Parse(strMD5Hash.Substring(16, 16), NumberStyles.HexNumber); + return String.Format("{0:x16}{1:x16}", uPartOne ^ uKey, uPartTwo ^ uKey); + } + + private static ulong[] MD5_To_Int(string strMD5Hash) + { + // Create new array + ulong[] uMD5Ints = new ulong[4]; + + // For each 8 characters we swap bytes and logically AND them + for (int i = 0; i < strMD5Hash.Length; i += 8) + uMD5Ints[i / 8] = ulong.Parse(Swap_Bytes(strMD5Hash.Substring(i, 8), 2), NumberStyles.HexNumber) & 0x7FFFFFFF; + + // Return the array of integers + return uMD5Ints; + } + + private static ulong[] CHLID_To_Int(string strCHLID) + { + // Create new arrays + ulong[] uCHLIDInts = new ulong[strCHLID.Length / 4]; + + // For each 4 characters we swap bytes and convert to integers + for (int i = 0; i < strCHLID.Length; i += 4) + uCHLIDInts[i / 4] = ulong.Parse(Swap_Bytes(To_Hex(Encoding.Default.GetBytes(strCHLID.Substring(i, 4))), 2), NumberStyles.HexNumber); + + // Return the array of integers + return uCHLIDInts; + } + + private static ulong Create_Key(ulong[] uMD5Ints, ulong[] uCHLIDInts) + { + // Walk over each two elements in the uCHLIDInts array + ulong temp = 0, high = 0, low = 0; + for (int i = 0; i < uCHLIDInts.Length; i += 2) + { + // First multiply by a constant, modulo and add the high key + // Then multiply by the first MD5Int, add the second and modulo again + temp = ((uCHLIDInts[i] * 0x0E79A9C1) % 0x7FFFFFFF) + high; + temp = ((temp * uMD5Ints[0]) + uMD5Ints[1]) % 0x7FFFFFFF; + + // Add the i+1 to the temp variable and modulo + // Then multiply by the third MD5Int and add the fourth, modulo! + high = (uCHLIDInts[i + 1] + temp) % 0x7FFFFFFF; + high = ((high * uMD5Ints[2]) + uMD5Ints[3]) % 0x7FFFFFFF; + + // Add both high and temp to low + low += high + temp; + } + + // Add some more MD5Ints and modulo again, also swap bytes around + high = ulong.Parse(Swap_Bytes(String.Format("{0:x8}", (high + uMD5Ints[1]) % 0x7FFFFFFF), 2), NumberStyles.HexNumber); + low = ulong.Parse(Swap_Bytes(String.Format("{0:x8}", (low + uMD5Ints[3]) % 0x7FFFFFFF), 2), NumberStyles.HexNumber); + + // Bitshift the high value 32 bits to the left and add low, then return it + return (high << 32) + low; + } + + private static string To_Hex(byte[] bBinary) + { + // For each character encode it + string strHex = ""; + foreach (byte i in bBinary) + strHex += Convert.ToString(i, 16).PadLeft(2, '0'); + + // Return the new stirng + return strHex; + } + + private static string Swap_Bytes(string strString, int iStep) + { + // Walk over each iStep characters + string strNewString = ""; + for (int i = 0; i < strString.Length; i += iStep) + strNewString = strString.Substring(i, iStep) + strNewString; + + // Return the result + return strNewString; + } + } +}; diff --git a/MSNPSharp/Resources/MSNPSharp_logo_128.png b/MSNPSharp/Resources/MSNPSharp_logo_128.png new file mode 100644 index 0000000..01df908 Binary files /dev/null and b/MSNPSharp/Resources/MSNPSharp_logo_128.png differ diff --git a/MSNPSharp/Resources/WLXLarge_default.gif b/MSNPSharp/Resources/WLXLarge_default.gif new file mode 100644 index 0000000..1d51495 Binary files /dev/null and b/MSNPSharp/Resources/WLXLarge_default.gif differ diff --git a/MSNPSharp/Resources/msnpsharp.snk b/MSNPSharp/Resources/msnpsharp.snk new file mode 100644 index 0000000..af52857 Binary files /dev/null and b/MSNPSharp/Resources/msnpsharp.snk differ diff --git a/MSNPSharp/SBMessageHandler.cs b/MSNPSharp/SBMessageHandler.cs new file mode 100644 index 0000000..b7b69dc --- /dev/null +++ b/MSNPSharp/SBMessageHandler.cs @@ -0,0 +1,1821 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Web; +using System.Text; +using System.Threading; +using System.Diagnostics; +using System.Collections; +using System.Collections.Generic; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + using MSNPSharp.DataTransfer; + + #region Event argument classes + /// + /// Used when a new switchboard session is affected. + /// + public class SBEventArgs : EventArgs + { + /// + /// + private SBMessageHandler switchboard; + + /// + /// The affected switchboard + /// + public SBMessageHandler Switchboard + { + get + { + return switchboard; + } + set + { + switchboard = value; + } + } + + /// + /// Constructor. + /// + public SBEventArgs(SBMessageHandler switchboard) + { + this.switchboard = switchboard; + } + } + + /// + /// Used when a new switchboard session is created. + /// + public class SBCreatedEventArgs : EventArgs + { + private object initiator; + private SBMessageHandler switchboard; + private string account = string.Empty; + private string name = string.Empty; + private bool anonymous = false; + + /// + /// The affected switchboard + /// + public SBMessageHandler Switchboard + { + get + { + return switchboard; + } + set + { + switchboard = value; + } + } + + + /// + /// The object that requested the switchboard. Null if the switchboard session was initiated by a remote client. + /// + public object Initiator + { + get + { + return initiator; + } + } + + /// + /// The account of user that requested the switchboard. + /// + public string Account + { + get + { + return account; + } + } + + /// + /// The nick name of user that requested the switchboard. + /// + public string Name + { + get + { + return name; + } + } + + /// + /// Anonymous request, usually from webchat users. + /// + public bool Anonymous + { + get + { + return anonymous; + } + } + + /// + /// Constructor. + /// + public SBCreatedEventArgs(SBMessageHandler switchboard, object initiator) + { + this.switchboard = switchboard; + this.initiator = initiator; + } + + /// + /// Constructor. + /// + public SBCreatedEventArgs(SBMessageHandler switchboard, object initiator, string account, string name, bool anonymous) + { + this.switchboard = switchboard; + this.initiator = initiator; + this.account = account; + this.name = name; + this.anonymous = anonymous; + } + } + + /// + /// Use when the acknowledgement of a message received. + /// + public class SBMessageDeliverResultEventArgs : SBEventArgs + { + private bool success = false; + + /// + /// Whether the specified message has been successfully delivered. + /// + public bool Success + { + get { return success; } + } + + private int messageID = 0; + + /// + /// The transision ID of the message. + /// + public int MessageID + { + get { return messageID; } + } + + public SBMessageDeliverResultEventArgs(bool success, int transId, SBMessageHandler switchBoard) + : base(switchBoard) + { + this.success = success; + messageID = transId; + } + } + + #endregion + + /// + /// Handles the text messages from the switchboard server.
+ /// Text messages includes the user typing message, plain text messages and nudge messages. + ///
+ public class SBMessageHandler : IMessageHandler + { + private SBMessageHandler() + { + } + + protected virtual void Initialize(NSMessageHandler handler) + { + nsMessageHandler = handler; + SetNewProcessor(); + + ResigerHandlersToProcessor(MessageProcessor); + NSMessageHandler.P2PHandler.AddSwitchboardSession(this); + NSMessageHandler.ContactOffline += new EventHandler(ContactOfflineHandler); + } + + /// + /// Constructor + /// + protected internal SBMessageHandler(NSMessageHandler handler) + { + Initialize(handler); + } + + /// + /// Constructor + /// + protected internal SBMessageHandler(NSMessageHandler handler, Contact callingContact, string sessionHash, string sessionId) + { + Initialize(handler); + + SessionId = sessionId; + SessionHash = sessionHash; + this.invited = true; + + NSMessageHandler.SetSession(SessionId, SessionHash); + + } + + #region Public Events + + /// + /// Fired when the owner is the only contact left. If the owner leaves too the connection is automatically closed by the server. + /// + public event EventHandler AllContactsLeft; + + /// + /// Fired when the session is closed, either by the server or by the local client. + /// + public event EventHandler SessionClosed; + + /// + /// Fired when a switchboard connection has been made and the initial handshaking commands are send. This indicates that the session is ready to invite or accept other contacts. + /// + public event EventHandler SessionEstablished; + + /// + /// Fired when a contact joins. In case of a conversation with two people in it this event is called with the remote contact specified in the event argument. + /// + public event EventHandler ContactJoined; + + /// + /// Fired when a contact leaves the conversation. + /// + public event EventHandler ContactLeft; + + /// + /// Fired when a message is received from any of the other contacts in the conversation. + /// + public event EventHandler TextMessageReceived; + + /// + /// Fired when a contact sends a emoticon definition. + /// + public event EventHandler EmoticonDefinitionReceived; + + /// + /// Fired when a contact sends a wink. + /// + public event EventHandler WinkReceived; + + /// + /// Fired when a contact sends a nudge. + /// + public event EventHandler NudgeReceived; + + /// + /// Fired when any of the other contacts is typing a message. + /// + public event EventHandler UserTyping; + + /// + /// Fired when an exception is thrown while handling the incoming or outgoing messages. + /// + public event EventHandler ExceptionOccurred; + + /// + /// Fired when the MSN Switchboard Server sends us an error. + /// + public event EventHandler ServerErrorReceived; + + /// + /// Fired when the MSN Switchboard Server sends us an acknowledgement (ACK or NAK). + /// + public event EventHandler MessageAcknowledgementReceived; + + #endregion + + #region Members + + private Dictionary rosterName = new Dictionary(0); + private Dictionary rosterCapacities = new Dictionary(0); + private Dictionary rosterState = new Dictionary(0); + + private Dictionary multiPacketMessages = new Dictionary(); + private object syncObject = new object(); + private Queue invitationQueue = new Queue(); + + protected SocketMessageProcessor messageProcessor = null; + private NSMessageHandler nsMessageHandler = null; + + private string sessionId = string.Empty; + private string sessionHash = string.Empty; + protected bool sessionEstablished = false; + protected bool invited = false; + private bool waitingForRing = false; + + #endregion + + #region Properties + + /// + /// The nameserver that received the request for the switchboard session + /// + internal NSMessageHandler NSMessageHandler + { + get + { + return nsMessageHandler; + } + } + + /// + /// Indicates if the local client was invited to the session + /// + public bool Invited + { + get + { + return invited; + } + } + + /// + /// Indicates if the session is ready to send/accept commands. E.g. the initial handshaking and identification has been completed. + /// + public bool IsSessionEstablished + { + get + { + return sessionEstablished; + } + + private set + { + sessionEstablished = value; + } + } + + protected string SessionId + { + get + { + return sessionId; + } + + set + { + sessionId = value; + } + } + + + /// + /// The hash identifier used to define this switchboard session. + /// + internal string SessionHash + { + get + { + return sessionHash; + } + + private set + { + sessionHash = value; + } + } + + /// + /// Implements the P2P framework. This object is automatically created when a succesfull connection was made to the switchboard. + /// + [Obsolete("Please use Messenger.P2PHandler.", true)] + public P2PHandler P2PHandler + { + get + { + throw new MSNPSharpException("Please use Messenger.P2PHandler."); + } + set + { + throw new MSNPSharpException("Please use Messenger.P2PHandler."); + } + } + + #endregion + + #region Invitation + + /// + /// Invites the specified contact to the switchboard. + /// + /// + /// If there is not yet a connection established the invitation will be stored in a queue and processed as soon as a connection is established. + /// + /// The contact's account to invite. + public virtual bool Invite(Contact contact) + { + return Invite(contact, Guid.Empty); + } + + /// + /// Called when a switchboard session is created on request of a local client. + /// + /// + public void SetInvitation(string sessionHash) + { + SessionHash = sessionHash; + SessionId = SessionHash.Split('.')[0]; + + NSMessageHandler.SetSession(SessionId, SessionHash); + + this.invited = false; + } + + /// + /// Left the current switchboard conversation. + /// + public void Left() + { + MessageProcessor.SendMessage(new SBMessage("OUT", new string[] { })); + } + + public virtual void Close() + { + Close(false); + } + + /// + /// Left the conversation then closes the switchboard session by disconnecting from the server. + /// + protected virtual void Close(bool causeByRemote) + { + if (MessageProcessor != null) + { + if (!causeByRemote) + { + SendSwitchBoardClosedNotifyToNS(); + } + + try + { + SocketMessageProcessor processor = MessageProcessor as SocketMessageProcessor; + if (processor != null) + { + if (processor.Connected) + { + + //We want to left the conversation, say "OUT" to SB. + Left(); + processor.Disconnect(); + } + + } + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, ex.Message, GetType().ToString()); + } + finally + { + + MessageProcessor.UnregisterHandler(this); + } + } + + if (IsSessionEstablished) + { + OnSessionClosed(); + } + } + + #endregion + + #region Messaging + + /// + /// Sends a plain text message to all other contacts in the conversation. + /// + /// + /// This method wraps the TextMessage object in a SBMessage object and sends it over the network. + /// + /// The message to send. + public virtual void SendTextMessage(TextMessage message) + { + + //First, we have to check whether the content of the message is not to big for one message + //There's a maximum of 1600 bytes per message, let's play safe and take 1400 bytes + UTF8Encoding encoding = new UTF8Encoding(); + + if (encoding.GetByteCount(message.Text) > 1400) + { + //we'll have to use multi-packets messages + Guid guid = Guid.NewGuid(); + byte[] text = encoding.GetBytes(message.Text); + int chunks = Convert.ToInt32(Math.Ceiling((double)text.GetUpperBound(0) / (double)1400)); + for (int i = 0; i < chunks; i++) + { + SBMessage sbMessage = new SBMessage(); + sbMessage.Acknowledgement = "N"; + + //Clone the message + TextMessage chunkMessage = (TextMessage)message.Clone(); + + //Get the part of the message that we are going to send + if (text.GetUpperBound(0) - (i * 1400) > 1400) + chunkMessage.Text = encoding.GetString(text, i * 1400, 1400); + else + chunkMessage.Text = encoding.GetString(text, i * 1400, text.GetUpperBound(0) - (i * 1400)); + + MimeMessage msgMessage = WrapMessage(chunkMessage); + + //Add the correct headers + msgMessage.MimeHeader.Add("Message-ID", "{" + guid.ToString() + "}"); + + if (i == 0) + msgMessage.MimeHeader.Add("Chunks", Convert.ToString(chunks)); + else + msgMessage.MimeHeader.Add("Chunk", Convert.ToString(i)); + + sbMessage.InnerMessage = msgMessage; + + //send it over the network + MessageProcessor.SendMessage(sbMessage); + } + } + else + { + SBMessage sbMessage = new SBMessage(); + sbMessage.Acknowledgement = "N"; + + sbMessage.InnerMessage = WrapMessage(message); + + // send it over the network + MessageProcessor.SendMessage(sbMessage); + } + } + + /// + /// Sends the definition for a list of emoticons to all other contacts in the conversation. The client-programmer must use this function if a text messages uses multiple emoticons in a single message. + /// + /// Use this function before sending text messages which include the emoticon text. You can only send one emoticon message before the textmessage. So make sure that all emoticons used in the textmessage are included. + /// A list of emoticon objects. + /// The type of current emoticons. + public virtual void SendEmoticonDefinitions(List emoticons, EmoticonType icontype) + { + if (emoticons == null) + throw new ArgumentNullException("emoticons"); + + foreach (Emoticon emoticon in emoticons) + { + if (!NSMessageHandler.ContactList.Owner.Emoticons.ContainsKey(emoticon.Sha)) + { + // Add the emotions to owner's emoticon collection. + NSMessageHandler.ContactList.Owner.Emoticons.Add(emoticon.Sha, emoticon); + } + } + + EmoticonMessage emoticonMessage = new EmoticonMessage(emoticons, icontype); + + SBMessage sbMessage = new SBMessage(); + sbMessage.Acknowledgement = "N"; + sbMessage.InnerMessage = WrapMessage(emoticonMessage); + + // send it over the network + MessageProcessor.SendMessage(sbMessage); + } + + /// + /// Sends a 'user is typing..' message to the switchboard, and is received by all participants. + /// + public virtual void SendTypingMessage() + { + SBMessage sbMessage = new SBMessage(); + sbMessage.Acknowledgement = "U"; + + MimeMessage mimeMessage = new MimeMessage(); + mimeMessage.MimeHeader[MimeHeaderStrings.Content_Type] = "text/x-msmsgscontrol"; + + mimeMessage.MimeHeader[MimeHeaderStrings.TypingUser] = NSMessageHandler.ContactList.Owner.Mail.ToLowerInvariant(); + + mimeMessage.InnerMessage = new TextPayloadMessage("\r\n"); + + sbMessage.InnerMessage = mimeMessage; + + MessageProcessor.SendMessage(sbMessage); + } + + /// + /// Sends a 'nudge' message to the switchboard, and is received by all participants. + /// + public virtual void SendNudge() + { + // send it over the network + SBMessage sbMessage = new SBMessage(); + + MimeMessage mimeMessage = new MimeMessage(); + mimeMessage.MimeHeader[MimeHeaderStrings.Content_Type] = "text/x-msnmsgr-datacast"; + + MimeMessage innerMimeMessage = new MimeMessage(false); + innerMimeMessage.MimeHeader["ID"] = "1"; + + mimeMessage.InnerMessage = innerMimeMessage; + + sbMessage.InnerMessage = mimeMessage; + + MessageProcessor.SendMessage(sbMessage); + } + + /// + /// Send a keep-alive message to avoid the switchboard closing. This is useful for bots. + /// + public virtual void SendKeepAliveMessage() + { + SBMessage sbMessage = new SBMessage(); + + MimeMessage mimeMessage = new MimeMessage(); + mimeMessage.MimeHeader[MimeHeaderStrings.Content_Type] = "text/x-keepalive"; + + mimeMessage.InnerMessage = new TextPayloadMessage("\r\n"); + + sbMessage.InnerMessage = mimeMessage; + + MessageProcessor.SendMessage(sbMessage); + } + + #endregion + + #region Protected User Methods + + /// + /// Fires the event. + /// + protected virtual void OnAllContactsLeft() + { + if (AllContactsLeft != null) + { + AllContactsLeft(this, new EventArgs()); + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, ToString() + " all contacts left, disconnect automately.", GetType().ToString()); + Close(false); + } + + /// + /// Fires the event. + /// + /// The contact who joined the session. + /// The machine guid where this contact joined from. + protected virtual void OnContactJoined(Contact contact, Guid endPoint) + { + if (ContactJoined != null) + { + ContactJoined(this, new ContactConversationEventArgs(contact, endPoint)); + } + } + + /// + /// Fires the event. + /// + /// The contact who left the session. + /// The machine guid where this contact left from. + protected virtual void OnContactLeft(Contact contact, Guid endPoint) + { + if (ContactLeft != null) + { + ContactLeft(this, new ContactConversationEventArgs(contact, endPoint)); + } + } + + /// + /// Fires the event. + /// + /// The emoticon message. + /// The contact who is sending the definition. + protected virtual void OnEmoticonDefinition(MimeMessage message, Contact contact) + { + EmoticonMessage emoticonMessage = new EmoticonMessage(); + emoticonMessage.CreateFromParentMessage(message); + + if (EmoticonDefinitionReceived != null) + { + foreach (Emoticon emoticon in emoticonMessage.Emoticons) + { + EmoticonDefinitionReceived(this, new EmoticonDefinitionEventArgs(contact, emoticon)); + } + } + } + + /// + /// Fires the event. + /// + /// The contact who is sending the nudge. + protected virtual void OnNudgeReceived(Contact contact) + { + if (NudgeReceived != null) + { + NudgeReceived(this, new ContactEventArgs(contact)); + } + } + + /// + /// Fires the event. + /// + /// The contact who is typing. + protected virtual void OnUserTyping(Contact contact) + { + // make sure we don't parse the rest of the message in the next loop + if (UserTyping != null) + { + // raise the event + UserTyping(this, new ContactEventArgs(contact)); + } + } + + protected virtual void OnWinkReceived(MimeMessage message, Contact contact) + { + string body = System.Text.Encoding.UTF8.GetString(message.InnerBody); + + Wink obj = new Wink(); + obj.SetContext(body, false); + + if (WinkReceived != null) + WinkReceived(this, new WinkEventArgs(contact, obj)); + } + + /// + /// Fires the event. + /// + /// The message send. + /// The contact who sended the message. + protected virtual void OnTextMessageReceived(TextMessage message, Contact contact) + { + if (TextMessageReceived != null) + TextMessageReceived(this, new TextMessageEventArgs(message, contact)); + } + + protected virtual void OnMessageAcknowledgementReceived(SBMessageDeliverResultEventArgs args) + { + if (MessageAcknowledgementReceived != null) + MessageAcknowledgementReceived(this, args); + } + + /// + /// Fires the SessionClosed event. + /// + protected virtual void OnSessionClosed() + { + IsSessionEstablished = false; + ClearAll(); //Session closed, force all contact left this conversation. + + if (SessionClosed != null) + SessionClosed(this, new EventArgs()); + } + + /// + /// Fires the SessionEstablished event and processes invitations in the queue. + /// + protected virtual void OnSessionEstablished() + { + IsSessionEstablished = true; + if (SessionEstablished != null) + SessionEstablished(this, new EventArgs()); + + // process ant remaining invitations + SendOneQueuedInvitation(); + } + + /// + /// Handles all remaining invitations. If no connection is yet established it will do nothing. + /// + protected virtual void SendOneQueuedInvitation() + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Processing invitations for switchboard...", GetType().Name); + + lock (syncObject) + { + if (IsSessionEstablished && !waitingForRing) + { + if (invitationQueue.Count > 0) + { + Contact targetContact = invitationQueue.Dequeue(); + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Invitation to contact " + targetContact + " has been sent.", GetType().Name); + SendInvitationCommand(targetContact); + waitingForRing = true; + } + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Invitation to contact request has been denied since SwitchBoard session is in waitingForRING status."); + } + } + } + + /// + /// Sends the invitation command to the switchboard server. + /// + /// + protected virtual void SendInvitationCommand(Contact contact) + { + MessageProcessor.SendMessage(new SBMessage("CAL", new string[] { contact.Mail })); + } + + /// + /// Send the first message to the server. + /// + /// + /// Depending on the field a ANS command (if true), or a USR command (if false) is send. + /// + protected virtual void SendInitialMessage() + { + string auth = NSMessageHandler.ContactList.Owner.Mail + ";" + NSMessageHandler.MachineGuid.ToString("B"); + + if (Invited) + MessageProcessor.SendMessage(new SBMessage("ANS", new string[] { auth, SessionHash, SessionId.ToString(System.Globalization.CultureInfo.InvariantCulture) })); + else + MessageProcessor.SendMessage(new SBMessage("USR", new string[] { auth, SessionHash })); + } + + protected virtual void SendSwitchBoardClosedNotifyToNS() + { + NSMessageHandler.SendSwitchBoardClosedNotify(SessionId.ToString()); + } + + protected virtual void SetNewProcessor() + { + messageProcessor = new SBMessageProcessor(NSMessageHandler.ConnectivitySettings); + + // catch the connect event to start sending the USR command upon initiating + messageProcessor.ConnectionEstablished += OnProcessorConnectCallback; + messageProcessor.ConnectionClosed += OnProcessorDisconnectCallback; + } + + protected virtual void ResigerHandlersToProcessor(IMessageProcessor processor) + { + if (processor != null) + { + processor.RegisterHandler(this); + processor.RegisterHandler(NSMessageHandler.P2PHandler); + } + } + + protected virtual void SetRosterProperty(string key, string value, RosterProperties property) + { + switch (property) + { + case RosterProperties.Name: + lock (rosterName) + rosterName[key.ToLowerInvariant()] = value; + break; + case RosterProperties.ClientCapacityString: + lock (rosterCapacities) + rosterCapacities[key.ToLowerInvariant()] = value; + break; + case RosterProperties.Status: + lock (rosterState) + rosterState[key.ToLowerInvariant()] = (ContactConversationState)Enum.Parse(typeof(ContactConversationState), value); + break; + } + } + + protected virtual bool IsAllContactsInRosterLeft() + { + lock (rosterState) + { + foreach (string key in rosterState.Keys) + { + if (rosterState[key] != ContactConversationState.Left && + NSMessageHandler.ContactList.Owner != null && + EndPointData.GetAccountFromUniqueEPIDString(key) != NSMessageHandler.ContactList.Owner.Mail.ToLowerInvariant()) + { + // If: There is only one owner without any endpoint id, the switchboard is ended. + // If: There is/are owner(s) with endpoint id(s) and status is/are not left, keep the switch available. + return false; + } + } + + return true; + } + } + + protected virtual bool Invite(Contact contact, Guid endPoint) + { + string fullaccount = contact.Mail.ToLowerInvariant(); + object status = null; + + if (endPoint != Guid.Empty) + { + fullaccount += ";" + endPoint.ToString("B").ToLowerInvariant(); + } + + status = GetRosterProperty(fullaccount, RosterProperties.Status); + if (status != null) + { + if (((ContactConversationState)status) != ContactConversationState.Left) + { + //Invite repeatly. + return false; + } + } + + //Add "this contact" + SetRosterProperty(fullaccount, ContactConversationState.Invited.ToString(), RosterProperties.Status); + + if (endPoint == Guid.Empty) + { + //Add "all contact" + SetRosterProperty(contact.Mail.ToLowerInvariant(), ContactConversationState.Invited.ToString(), RosterProperties.Status); + if (contact.HasSignedInWithMultipleEndPoints) //Set every enpoints as Invited. + { + foreach (Guid epId in contact.EndPointData.Keys) + { + if (epId == Guid.Empty) continue; + string currentAccount = contact.Mail.ToLowerInvariant() + ";" + epId.ToString("B").ToLowerInvariant(); + SetRosterProperty(currentAccount, ContactConversationState.Invited.ToString(), RosterProperties.Status); + } + } + } + + invitationQueue.Enqueue(contact); + SendOneQueuedInvitation(); + + return true; + } + + protected virtual object GetRosterProperty(string key, RosterProperties property) + { + string value = string.Empty; + string lowerKey = key.ToLowerInvariant(); + + switch (property) + { + case RosterProperties.Name: + lock (rosterName) + { + if (!rosterName.ContainsKey(lowerKey)) + return null; + return rosterName[lowerKey]; + } + + case RosterProperties.ClientCapacities: + lock (rosterCapacities) + { + if (!rosterCapacities.ContainsKey(lowerKey)) + return null; + + value = rosterCapacities[lowerKey]; + int cap = 0; + if (value.Contains(":")) + { + int.TryParse(value.Split(':')[0], out cap); + return (ClientCapacities)cap; + } + + return ClientCapacities.None; + } + + case RosterProperties.ClientCapacitiesEx: + lock (rosterCapacities) + { + if (!rosterCapacities.ContainsKey(lowerKey)) + return null; + + value = rosterCapacities[lowerKey]; + int cap = 0; + if (value.Contains(":")) + { + int.TryParse(value.Split(':')[1], out cap); + return (ClientCapacitiesEx)cap; + } + + return ClientCapacitiesEx.None; + } + case RosterProperties.ClientCapacityString: + lock (rosterCapacities) + { + if (!rosterCapacities.ContainsKey(lowerKey)) + return null; + return rosterCapacities[lowerKey]; + } + case RosterProperties.Status: + lock (rosterState) + { + if (!rosterState.ContainsKey(lowerKey)) + return null; + return rosterState[lowerKey]; + } + } + + return null; + } + + protected virtual void ContactOfflineHandler(object sender, ContactEventArgs e) + { + Contact contact = e.Contact; + + if (HasContact(contact) && GetRosterUniqueUserCount() == 1) + { + Close(true); + } + } + + internal virtual int GetRosterUserCount() + { + int count = 0; + lock (rosterState) + { + foreach (string key in rosterState.Keys) + { + if (NSMessageHandler.ContactList.Owner != null) + { + if (EndPointData.GetAccountFromUniqueEPIDString(key) != NSMessageHandler.ContactList.Owner.Mail.ToLowerInvariant()) + { + count++; + } + } + } + + return count; + } + } + + internal virtual int GetRosterUniqueUserCount() + { + Dictionary uniqueUsers = new Dictionary(0); + + lock (rosterState) + { + foreach (string key in rosterState.Keys) + { + if (NSMessageHandler.ContactList.Owner != null) + { + uniqueUsers[EndPointData.GetAccountFromUniqueEPIDString(key)] = string.Empty; + } + } + + return uniqueUsers.Count; + } + } + + internal bool HasContact(Contact contact) + { + lock (rosterState) + { + if (HasContact(contact.Mail)) + return true; + + if (HasContact(contact.Mail, contact.Guid)) + return true; + + lock (contact.SyncObject) + { + foreach (Guid epId in contact.EndPointData.Keys) + { + if (epId == Guid.Empty) continue; + + if (HasContact(contact.Mail, epId)) + return true; + } + } + + return false; + } + } + + internal bool HasContact(string uniqueEndPointIDString) + { + lock (rosterState) + return rosterState.ContainsKey(uniqueEndPointIDString.ToLowerInvariant()); + } + + internal bool HasContact(string account, Guid place) + { + string fullaccount = account.ToLowerInvariant() + ";" + place.ToString("B").ToLowerInvariant(); + lock (rosterState) + return rosterState.ContainsKey(fullaccount); + } + + #endregion + + #region Protected CMDs + + /// + /// Called when a ANS command has been received. + /// + /// + /// Indicates that the server has replied to our identification ANS command. + /// ANS [Transaction] ['OK'] + /// + /// + protected virtual void OnANSReceived(SBMessage message) + { + if (message.CommandValues[0].ToString() == "OK") + { + // we are now ready to invite other contacts. Notify the client of this. + OnSessionEstablished(); + } + } + + /// + /// Called when a BYE command has been received. + /// + /// + /// Indicates that a remote contact has leaved the session. + /// This will fire the event. Or, if all contacts have left, the event. + /// BYE [account[;GUID]] [Client Type] + /// + /// + protected virtual void OnBYEReceived(SBMessage message) + { + string fullaccount = message.CommandValues[0].ToString().ToLowerInvariant(); + + ContactConversationState oldStatus = ContactConversationState.None; + object result = GetRosterProperty(fullaccount, RosterProperties.Status); + if (result != null) + { + oldStatus = (ContactConversationState)(result); + } + + if (oldStatus == ContactConversationState.Left || oldStatus == ContactConversationState.None) + return; + + SetRosterProperty(fullaccount, ContactConversationState.Left.ToString(), RosterProperties.Status); + + Guid endPointId = Guid.Empty; + string account = fullaccount; + + if (fullaccount.Contains(";")) + { + string[] accountGuid = fullaccount.Split(';'); + account = accountGuid[0]; + endPointId = new Guid(accountGuid[1]); + } + + if (NSMessageHandler.ContactList.Owner != null && account == NSMessageHandler.ContactList.Owner.Mail.ToLowerInvariant()) + { + if (IsAllContactsInRosterLeft()) + { + OnAllContactsLeft(); + } + return; + } + + Contact contact = (message.CommandValues.Count >= 2) ? + NSMessageHandler.ContactList.GetContact(account, (ClientType)Enum.Parse(typeof(ClientType), message.CommandValues[1].ToString())) + : + NSMessageHandler.ContactList.GetContact(account, ClientType.PassportMember); + + OnContactLeft(contact, endPointId); // notify the client programmer + + if (IsAllContactsInRosterLeft()) + { + OnAllContactsLeft(); //Indicates whe should end the conversation and disconnect. + } + } + + /// + /// Called when a CAL command has been received. + /// + /// + /// Indicates that the server has replied to our request to invite a contact. + /// CAL [Transaction] ['RINGING'] [sessionId] + /// + /// + protected virtual void OnCALReceived(SBMessage message) + { + lock (syncObject) + { + if (waitingForRing) + { + waitingForRing = false; + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "CAL RINGING received, watingForRING status has been reset."); + SendOneQueuedInvitation(); + + } + } + } + + /// + /// Called when a NAK command has been received. Inidcates switch board failed to deliver a message to the target contact. + /// + /// + /// NAK [MSGTransid] + /// + /// + protected virtual void OnNAKReceived(SBMessage message) + { + OnMessageAcknowledgementReceived(new SBMessageDeliverResultEventArgs(false, message.TransactionID, this)); + } + + /// + /// Called when a IRO command has been received. + /// + /// + /// Indicates contacts in the session that have joined. + /// IRO [Transaction] [Current] [Total] [account[;GUID]] [DisplayName] [Caps] + /// + /// + protected virtual void OnIROReceived(SBMessage message) + { + string fullaccount = message.CommandValues[2].ToString().ToLowerInvariant(); + string displayName = MSNHttpUtility.NSDecode(message.CommandValues[3].ToString()); + string capacitiesString = message.CommandValues[4].ToString(); + + ContactConversationState oldStatus = ContactConversationState.None; + object result = GetRosterProperty(fullaccount, RosterProperties.Status); + if (result != null) + { + oldStatus = (ContactConversationState)(result); + } + + SetRosterProperty(fullaccount, displayName, RosterProperties.Name); + SetRosterProperty(fullaccount, capacitiesString, RosterProperties.ClientCapacityString); + SetRosterProperty(fullaccount, ContactConversationState.Joined.ToString(), RosterProperties.Status); + + string account = fullaccount; + bool supportMPOP = false; + Guid endpointGuid = Guid.Empty; + + if (fullaccount.Contains(";")) + { + supportMPOP = true; + account = fullaccount.Split(';')[0]; + endpointGuid = new Guid(fullaccount.Split(';')[1]); + } + + if (NSMessageHandler.ContactList.Owner.Mail.ToLowerInvariant() == account) + return; + + // Get the contact. + Contact contact = NSMessageHandler.ContactList.GetContact(account, ClientType.PassportMember); + + // Not in contact list (anonymous). Update it's name and caps. + if (contact.Lists == MSNLists.None || NSMessageHandler.BotMode) + { + contact.SetStatus(PresenceStatus.Online); + + if (supportMPOP) + { + if (contact.PersonalMessage == null) + { + PersonalMessage personalMessage = new PersonalMessage("", MediaType.None, new string[] { }, endpointGuid); + contact.SetPersonalMessage(personalMessage); + } + else + { + PersonalMessage personalMessage = new PersonalMessage(contact.PersonalMessage.Message, + contact.PersonalMessage.MediaType, contact.PersonalMessage.CurrentMediaContent, endpointGuid); + contact.SetPersonalMessage(personalMessage); + } + } + } + + if (message.CommandValues.Count >= 4) + contact.SetName(MSNHttpUtility.NSDecode(message.CommandValues[3].ToString())); + + if (message.CommandValues.Count >= 5) + { + string caps = message.CommandValues[4].ToString(); + UpdateContactEndPointData(contact, endpointGuid, caps, supportMPOP); + } + + + // Notify the client programmer. + if (oldStatus != ContactConversationState.Joined) + { + OnContactJoined(contact, endpointGuid); + } + } + + /// + /// Called when a JOI command has been received. + /// + /// + /// Indicates that a remote contact has joined the session. + /// This will fire the event. + /// JOI [account[;GUID]] [DisplayName] [Caps] + /// + /// + protected virtual void OnJOIReceived(SBMessage message) + { + string fullaccount = message.CommandValues[0].ToString().ToLowerInvariant(); + string displayName = MSNHttpUtility.NSDecode(message.CommandValues[1].ToString()); + string capacitiesString = message.CommandValues[2].ToString(); + + ContactConversationState oldStatus = ContactConversationState.None; + object result = GetRosterProperty(fullaccount, RosterProperties.Status); + if (result != null) + { + oldStatus = (ContactConversationState)(result); + } + + SetRosterProperty(fullaccount, displayName, RosterProperties.Name); + SetRosterProperty(fullaccount, capacitiesString, RosterProperties.ClientCapacityString); + SetRosterProperty(fullaccount, ContactConversationState.Joined.ToString(), RosterProperties.Status); + + string account = fullaccount; + bool supportMPOP = false; + Guid endpointGuid = Guid.Empty; + + if (fullaccount.Contains(";")) + { + supportMPOP = true; + account = fullaccount.Split(';')[0]; + endpointGuid = new Guid(fullaccount.Split(';')[1]); + } + + if (NSMessageHandler.ContactList.Owner.Mail.ToLowerInvariant() != account) + { + // Get the contact. + Contact contact = NSMessageHandler.ContactList.GetContact(account, ClientType.PassportMember); + + // Not in contact list (anonymous). Update it's name and caps. + if (contact.Lists == MSNLists.None || NSMessageHandler.BotMode) + { + contact.SetStatus(PresenceStatus.Online); + + if (supportMPOP) + { + if (contact.PersonalMessage == null) + { + PersonalMessage personalMessage = new PersonalMessage("", MediaType.None, new string[] { }, endpointGuid); + contact.SetPersonalMessage(personalMessage); + } + else + { + PersonalMessage personalMessage = new PersonalMessage(contact.PersonalMessage.Message, + contact.PersonalMessage.MediaType, contact.PersonalMessage.CurrentMediaContent, endpointGuid); + contact.SetPersonalMessage(personalMessage); + } + } + } + + if (message.CommandValues.Count >= 2) + contact.SetName(MSNHttpUtility.NSDecode(message.CommandValues[1].ToString())); + + if (message.CommandValues.Count >= 3) + { + string caps = message.CommandValues[2].ToString(); + UpdateContactEndPointData(contact, endpointGuid, caps, supportMPOP); + } + + + // Notify the client programmer. + if (oldStatus != ContactConversationState.Joined) + { + OnContactJoined(contact, endpointGuid); + } + } + } + + /// + /// Called when a USR command has been received. + /// + /// + /// Indicates that the server has replied to our identification USR command. + /// USR [Transaction] ['OK'] [account[;GUID]] [name] + /// + /// + protected virtual void OnUSRReceived(SBMessage message) + { + if (message.CommandValues[0].ToString() == "OK") + { + string account = message.CommandValues[1].ToString().ToLowerInvariant(); + if (account.Contains(";")) + { + account = account.Split(';')[0]; + } + + if (NSMessageHandler.ContactList.Owner.Mail.ToLowerInvariant() == account) + { + // update the owner's name. Just to be sure. + // NSMessageHandler.ContactList.Owner.SetName(message.CommandValues[2].ToString()); + if (NSMessageHandler != null) + { + Invite(NSMessageHandler.ContactList.Owner); + } + // we are now ready to invite other contacts. Notify the client of this. + OnSessionEstablished(); + } + } + } + + /// + /// Called when a MSG command has been received. + /// + /// + /// Indicates that a remote contact has send us a message. This can be a plain text message, + /// an invitation, or an application specific message. + /// MSG [Account] [Name] [Bodysize] + /// + /// + protected virtual void OnMSGReceived(MSNMessage message) + { + // the MSG command is the most versatile one. These are all the messages + // between clients. Like normal messages, file transfer invitations, P2P messages, etc. + Contact contact = NSMessageHandler.ContactList.GetContact(message.CommandValues[0].ToString(), ClientType.PassportMember); + + // update the name to make sure we have it up-to-date + //contact.SetName(message.CommandValues[1].ToString()); + + // get the corresponding SBMSGMessage object + MimeMessage sbMSGMessage = new MimeMessage(); + sbMSGMessage.CreateFromParentMessage(message); + + //first check if we are dealing with multi-packet-messages + if (sbMSGMessage.MimeHeader.ContainsKey("Message-ID")) + { + //is this the first message? + if (sbMSGMessage.MimeHeader.ContainsKey("Chunks")) + { + multiPacketMessages.Add(sbMSGMessage.MimeHeader["Message-ID"] + "/0", sbMSGMessage); + return; + } + + else if (sbMSGMessage.MimeHeader.ContainsKey("Chunk")) + { + //Is this the last message? + if (Convert.ToInt32(sbMSGMessage.MimeHeader["Chunk"]) + 1 == Convert.ToInt32(multiPacketMessages[sbMSGMessage.MimeHeader["Message-ID"] + "/0"].MimeHeader["Chunks"])) + { + //Paste all the pieces together + MimeMessage completeMessage = multiPacketMessages[sbMSGMessage.MimeHeader["Message-ID"] + "/0"]; + multiPacketMessages.Remove(sbMSGMessage.MimeHeader["Message-ID"] + "/0"); + + int chunksToProcess = Convert.ToInt32(completeMessage.MimeHeader["Chunks"]) - 2; + List completeText = new List(completeMessage.InnerBody); + for (int i = 0; i < chunksToProcess; i++) + { + MimeMessage part = multiPacketMessages[sbMSGMessage.MimeHeader["Message-ID"] + "/" + Convert.ToString(i + 1)]; + completeText.AddRange(part.InnerBody); + + //Remove the part from the buffer + multiPacketMessages.Remove(sbMSGMessage.MimeHeader["Message-ID"] + "/" + Convert.ToString(i + 1)); + } + + completeText.AddRange(sbMSGMessage.InnerBody); + completeMessage.InnerBody = completeText.ToArray(); + + //process the message + sbMSGMessage = completeMessage; + } + else + { + multiPacketMessages.Add(sbMSGMessage.MimeHeader["Message-ID"] + "/" + sbMSGMessage.MimeHeader["Chunk"], sbMSGMessage); + return; + } + } + else + throw new Exception("Multi-packetmessage with damaged headers received"); + } + + if (sbMSGMessage.MimeHeader.ContainsKey(MimeHeaderStrings.Content_Type)) + { + NetworkMessage actualMessage = null; + switch (sbMSGMessage.MimeHeader[MimeHeaderStrings.Content_Type].ToLower(System.Globalization.CultureInfo.InvariantCulture)) + { + case "text/x-msmsgscontrol": + actualMessage = new TextPayloadMessage(string.Empty); + break; + case "text/x-mms-emoticon": + case "text/x-mms-animemoticon": + actualMessage = new EmoticonMessage(); + break; + case "text/x-msnmsgr-datacast": + actualMessage = new MimeMessage(); + break; + default: + if (sbMSGMessage.MimeHeader[MimeHeaderStrings.Content_Type].ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf("text/plain") >= 0) + { + actualMessage = new TextMessage(); + } + break; + } + + if (actualMessage != null) + { + actualMessage.CreateFromParentMessage(sbMSGMessage); + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, message.ToDebugString(), GetType().Name); + } + + switch (sbMSGMessage.MimeHeader[MimeHeaderStrings.Content_Type].ToLower(System.Globalization.CultureInfo.InvariantCulture)) + { + case "text/x-msmsgscontrol": + // make sure we don't parse the rest of the message in the next loop + OnUserTyping(NSMessageHandler.ContactList.GetContact(sbMSGMessage.MimeHeader["TypingUser"], ClientType.PassportMember)); + break; + + case "text/x-mms-emoticon": + case "text/x-mms-animemoticon": + OnEmoticonDefinition(sbMSGMessage, contact); + break; + + case "text/x-msnmsgr-datacast": + if ((actualMessage as MimeMessage).MimeHeader.ContainsKey("ID")) + { + if ((actualMessage as MimeMessage).MimeHeader["ID"] == "1") + OnNudgeReceived(contact); + } + else if (message.CommandValues[2].Equals("1325")) + OnWinkReceived(sbMSGMessage, contact); + break; + + default: + if (sbMSGMessage.MimeHeader[MimeHeaderStrings.Content_Type].ToLower(System.Globalization.CultureInfo.InvariantCulture).IndexOf("text/plain") >= 0) + { + // a normal message has been sent, notify the client programmer + TextMessage msg = actualMessage as TextMessage; + OnTextMessageReceived(msg, contact); + } + break; + } + } + } + + /// + /// Called when a ACK command has been received. + /// + /// + /// ACK [MSGTransid] + /// + /// + protected virtual void OnACKReceived(SBMessage message) + { + OnMessageAcknowledgementReceived(new SBMessageDeliverResultEventArgs(true, message.TransactionID, this)); + } + + #endregion + + private void ClearAll() + { + lock (rosterState) + rosterState.Clear(); + lock (rosterName) + rosterName.Clear(); + lock (rosterCapacities) + rosterCapacities.Clear(); + } + + private MimeMessage WrapMessage(EmoticonMessage message) + { + MimeMessage msgParentMessage = new MimeMessage(); + if (message.EmoticonType == EmoticonType.StaticEmoticon) + msgParentMessage.MimeHeader[MimeHeaderStrings.Content_Type] = "text/x-mms-emoticon"; + else if (message.EmoticonType == EmoticonType.AnimEmoticon) + msgParentMessage.MimeHeader[MimeHeaderStrings.Content_Type] = "text-/x-mms-animemoticon"; + + msgParentMessage.InnerMessage = message; + + return msgParentMessage; + } + + private MimeMessage WrapMessage(TextMessage message) + { + MimeMessage msgParentMessage = new MimeMessage(); + msgParentMessage.MimeHeader[MimeHeaderStrings.Content_Type] = "text/plain; charset=UTF-8"; + msgParentMessage.MimeHeader[MimeHeaderStrings.X_MMS_IM_Format] = message.GetStyleString(); + + if (message.CustomNickname != string.Empty) + msgParentMessage.MimeHeader[MimeHeaderStrings.P4_Context] = message.CustomNickname; + + msgParentMessage.InnerMessage = message; + + return msgParentMessage; + } + + private void UpdateContactEndPointData(Contact contact, Guid endpointGuid, string caps, bool supportMPOP) + { + bool dump = false; + + if (caps.Contains(":")) + { + if (!contact.EndPointData.ContainsKey(endpointGuid)) + { + EndPointData epData = new EndPointData(contact.Mail, endpointGuid); + epData.ClientCapacities = (ClientCapacities)Convert.ToInt64(caps.Split(':')[0]); + epData.ClientCapacitiesEx = (ClientCapacitiesEx)Convert.ToInt64(caps.Split(':')[1]); + contact.EndPointData[endpointGuid] = epData; + dump = true; + } + + if (supportMPOP) + { + contact.EndPointData[endpointGuid].ClientCapacities = (ClientCapacities)Convert.ToInt64(caps.Split(':')[0]); + contact.EndPointData[endpointGuid].ClientCapacitiesEx = (ClientCapacitiesEx)Convert.ToInt64(caps.Split(':')[1]); + } + else + { + contact.EndPointData[Guid.Empty].ClientCapacities = (ClientCapacities)Convert.ToInt64(caps.Split(':')[0]); + contact.EndPointData[Guid.Empty].ClientCapacitiesEx = (ClientCapacitiesEx)Convert.ToInt64(caps.Split(':')[1]); + } + } + else + { + if (!contact.EndPointData.ContainsKey(endpointGuid)) + { + EndPointData epData = new EndPointData(contact.Mail, endpointGuid); + epData.ClientCapacities = (ClientCapacities)Convert.ToInt64(caps); + contact.EndPointData[endpointGuid] = epData; + dump = true; + } + + if (supportMPOP) + { + contact.EndPointData[endpointGuid].ClientCapacities = (ClientCapacities)Convert.ToInt64(caps); + } + else + { + contact.EndPointData[Guid.Empty].ClientCapacities = (ClientCapacities)Convert.ToInt64(caps); + } + } + + if (dump) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "EndPoint ID " + endpointGuid.ToString("B") + " not found in " + contact.ToString() + " new EndPointData added."); + } + } + + #region Switchboard Handling + + + + /// + /// Called when the message processor has established a connection. This function will + /// begin the login procedure by sending the USR or ANS command. + /// + protected virtual void OnProcessorConnectCallback(object sender, EventArgs e) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "OnProcessorConnectCallback: SB processor connected.", GetType().Name); + SendInitialMessage(); + } + + /// + /// Called when the message processor has disconnected. This function will + /// set the IsSessionEstablished to false. + /// + protected virtual void OnProcessorDisconnectCallback(object sender, EventArgs e) + { + if (IsSessionEstablished) //This means some exception occured and we drop out of the network. + { + Close(true); + } + } + + /// + /// The processor to handle the messages + /// + public IMessageProcessor MessageProcessor + { + get + { + return messageProcessor; + } + + set + { + throw new InvalidOperationException("This property is read-only."); + } + } + + + /// + /// Handles message from the processor. + /// + /// + /// This is one of the most important functions of the class. + /// It handles incoming messages and performs actions based on the commands in the messages. + /// Exceptions which occur in this method are redirected via the event. + /// + /// + /// The network message received from the notification server + public virtual void HandleMessage(IMessageProcessor sender, NetworkMessage message) + { + try + { + // We expect at least a SBMessage object + SBMessage sbMessage = (SBMessage)message; + + switch (sbMessage.Command) + { + case "ACK": + case "ANS": + case "BYE": + case "CAL": + case "IRO": + case "JOI": + case "USR": + case "NAK": + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, sbMessage.ToDebugString(), GetType().Name); + break; + } + + switch (sbMessage.Command) + { + case "MSG": + OnMSGReceived(sbMessage); + return; + case "ACK": + OnACKReceived(sbMessage); + return; + case "NAK": + OnNAKReceived(sbMessage); + return; + case "ANS": + OnANSReceived(sbMessage); + return; + case "BYE": + OnBYEReceived(sbMessage); + return; + case "CAL": + OnCALReceived(sbMessage); + return; + case "IRO": + OnIROReceived(sbMessage); + return; + case "JOI": + OnJOIReceived(sbMessage); + return; + case "USR": + OnUSRReceived(sbMessage); + return; + } + + // Check whether it is a numeric error command + if (sbMessage.Command[0] >= '0' && sbMessage.Command[0] <= '9') + { + try + { + int errorCode = int.Parse(sbMessage.Command, System.Globalization.CultureInfo.InvariantCulture); + OnServerErrorReceived((MSNError)errorCode); + } + catch (FormatException fe) + { + throw new MSNPSharpException("Exception occurred while parsing an error code received from the switchboard server", fe); + } + } + else + { + // It is a unknown command + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "UNKNOWN COMMAND: " + sbMessage.Command + "\r\n" + sbMessage.ToDebugString(), GetType().ToString()); + } + } + catch (Exception e) + { + OnExceptionOccurred(e); + throw; //RethrowToPreserveStackDetails (without e) + } + } + + /// + /// Fires the ServerErrorReceived event. + /// + protected virtual void OnServerErrorReceived(MSNError serverError) + { + if (ServerErrorReceived != null) + ServerErrorReceived(this, new MSNErrorEventArgs(serverError)); + } + + /// + /// Fires the event. + /// + /// The exception which was thrown + protected virtual void OnExceptionOccurred(Exception e) + { + if (ExceptionOccurred != null) + ExceptionOccurred(this, new ExceptionEventArgs(e)); + } + + #endregion + + /// + /// Debug string + /// + /// + public override string ToString() + { + return GetType().ToString() + " SessionHash: " + SessionHash; + } + + } +}; \ No newline at end of file diff --git a/MSNPSharp/SBMessageProcessor.cs b/MSNPSharp/SBMessageProcessor.cs new file mode 100644 index 0000000..47f545c --- /dev/null +++ b/MSNPSharp/SBMessageProcessor.cs @@ -0,0 +1,160 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Text; +using System.Collections; +using System.Diagnostics; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + using MSNPSharp.DataTransfer; + + + public class SBMessageProcessor : SocketMessageProcessor + { + int transactionID = 1; + + public event EventHandler HandlerException; + + protected internal SBMessageProcessor(ConnectivitySettings connectivitySettings) + : base(connectivitySettings) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Constructing object", GetType().Name); + + MessagePool = new SBMessagePool(); + } + + public int TransactionID + { + get + { + return transactionID; + } + set + { + transactionID = value; + } + } + + + protected int IncreaseTransactionID() + { + return ++transactionID; + } + + protected override void OnMessageReceived(byte[] data) + { + // first get the general expected switchboard message + SBMessage message = new SBMessage(); + + message.ParseBytes(data); + + // send the message + DispatchMessage(message); + } + + protected virtual void DispatchMessage(NetworkMessage message) + { + // copy the messageHandlers array because the collection can be + // modified during the message handling. (Handlers are registered/unregistered) + IMessageHandler[] handlers = MessageHandlers.ToArray(); + + // now give the handlers the opportunity to handle the message + foreach (IMessageHandler handler in handlers) + { + try + { + handler.HandleMessage(this, message); + } + catch (Exception e) + { + OnHandlerException(e); + } + } + } + + protected virtual void OnHandlerException(Exception e) + { + MSNPSharpException MSNPSharpException = new MSNPSharpException("An exception occured while handling a switchboard message. See inner exception for more details.", e); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, MSNPSharpException.InnerException.ToString() + "\r\nStacktrace:\r\n" + MSNPSharpException.InnerException.StackTrace.ToString(), GetType().Name); + + if (HandlerException != null) + HandlerException(this, new ExceptionEventArgs(MSNPSharpException)); + } + + protected virtual void DeliverToNetwork(SBMessage sbMessage) + { + sbMessage.TransactionID = IncreaseTransactionID(); + sbMessage.Acknowledgement = sbMessage.Acknowledgement; + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Outgoing message:\r\n" + sbMessage.ToDebugString() + "\r\n", GetType().Name); + + + int x = 0; + + if (sbMessage.CommandValues.Count > 0) + int.TryParse(sbMessage.CommandValues[0].ToString(), out x); + + Debug.Assert(x < 1500, "?"); + + + + // prepare the message + sbMessage.PrepareMessage(); + + // convert to bytes and send it over the socket + SendSocketData(sbMessage.GetBytes()); + } + + + + public override void SendMessage(NetworkMessage message) + { + SBMessage sbMessage = message as SBMessage; + + if (sbMessage == null) + { + throw new MSNPSharpException("Cannot use " + GetType().ToString() + " to deliver a " + message.GetType().ToString() + " message."); + } + + DeliverToNetwork(sbMessage); + } + + public override void Disconnect() + { + base.Disconnect(); + } + } +}; \ No newline at end of file diff --git a/MSNPSharp/Schedulers.cs b/MSNPSharp/Schedulers.cs new file mode 100644 index 0000000..43471f9 --- /dev/null +++ b/MSNPSharp/Schedulers.cs @@ -0,0 +1,345 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Text; +using System.Diagnostics; + +namespace MSNPSharp +{ + using MSNPSharp.DataTransfer; + using MSNPSharp.Core; + + /// + /// The queue object for scheduler. + /// + public class SchedulerQueueObject + { + IMessageProcessor messageProcessor = null; + NetworkMessage message = null; + Guid messengerId = Guid.Empty; + DateTime createTime = DateTime.MinValue; + + /// + /// The time this object created. + /// + public DateTime CreateTime + { + get { return createTime; } + } + + /// + /// The MessageProcessor who send the message. + /// + public IMessageProcessor MessageProcessor + { + get { return messageProcessor; } + } + + /// + /// The message need to be sent. + /// + public NetworkMessage Message + { + get { return message; } + } + + /// + /// The who schedule this message. + /// + public Guid MessengerId + { + get { return messengerId; } + } + + private SchedulerQueueObject() + { + } + + public SchedulerQueueObject(IMessageProcessor processor, NetworkMessage message, Guid owner) + { + messageProcessor = processor; + this.message = message; + messengerId = owner; + createTime = DateTime.Now; + } + } + + /// + /// Base form of a message scheduler. + /// + public interface IScheduler + { + int DelayTime + { + get; + set; + } + + void Enqueue(IMessageProcessor processor, NetworkMessage message, Guid ownerId); + Guid Register(Messenger messenger); + bool UnRegister(Guid id); + } + + /// + /// Delay sending the p2p invitation messages, avoid p2p data transfer request a new conversation. + /// + public class Scheduler : IScheduler + { + protected object syncObject = new object(); + private int delayTime = 5000; //In ms. + private Thread timerThread = null; + protected Queue messageQueue = new Queue(); + protected Dictionary messengerList = new Dictionary(0); + + /// + /// The sending interval for messages in message queue . + /// + public int DelayTime + { + get + { + return delayTime; + } + + set + { + delayTime = value; + } + } + + #region Private method + + protected virtual void EnqueueMessage(IMessageProcessor processor, NetworkMessage message, Guid ownerId) + { + if (processor == null || message == null) + return; + + lock (syncObject) + { + if (messengerList.ContainsKey(ownerId)) + { + messageQueue.Enqueue(new SchedulerQueueObject(processor, message, ownerId)); + } + } + } + + protected virtual void OnTimerCallback(object state) + { + while (true) + { + DateTime currentTime = DateTime.Now; + TimeSpan span = new TimeSpan(0, 0, 0, 0, DelayTime); + + lock (syncObject) + { + if (DequeueAndProcess(currentTime, span) == 0) + { + return; + } + } + + Thread.Sleep(span); + } + } + + + protected virtual int DequeueAndProcess(DateTime currentTime, TimeSpan span) + { + lock (syncObject) + { + while (messageQueue.Count > 0 && currentTime - messageQueue.Peek().CreateTime >= span) + { + SchedulerQueueObject item = messageQueue.Dequeue(); + if (messengerList.ContainsKey(item.MessengerId) && messengerList[item.MessengerId].Connected) + { + try + { + item.MessageProcessor.SendMessage(item.Message); + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, GetType().Name + " send bufferred message error: " + ex.Message); + } + } + } + + return messageQueue.Count; + } + } + + #endregion + + #region Public Method + + public Scheduler(int delay) + { + delayTime = delay; + timerThread = new Thread(new ParameterizedThreadStart(OnTimerCallback)); + } + + /// + /// Add the message to sending queue. + /// + /// + /// + /// + public virtual void Enqueue(IMessageProcessor processor, NetworkMessage message, Guid ownerId) + { + lock (syncObject) + { + if (messengerList.ContainsKey(ownerId)) + { + if (timerThread.ThreadState == System.Threading.ThreadState.Unstarted || + timerThread.ThreadState == System.Threading.ThreadState.Stopped) + { + EnqueueMessage(processor, message, ownerId); + + timerThread = new Thread(new ParameterizedThreadStart(OnTimerCallback)); + timerThread.Start(DelayTime); + return; + } + + EnqueueMessage(processor, message, ownerId); + } + else + { + return; + } + } + + } + + public virtual Guid Register(Messenger messenger) + { + lock (syncObject) + { + foreach (Guid guid in messengerList.Keys) + { + if (object.ReferenceEquals(messenger, messengerList[guid])) + { + return guid; + } + } + + Guid newId = Guid.NewGuid(); + while (messengerList.ContainsKey(newId)) + { + newId = Guid.NewGuid(); + } + + messengerList[newId] = messenger; + return newId; + } + } + + public virtual bool UnRegister(Guid id) + { + lock (syncObject) + { + return messengerList.Remove(id); + } + } + + #endregion + } + + /// + /// The for switchboard request. The scheduler will only send one request every second. + /// + public class SwitchBoardRequestScheduler : Scheduler + { + public SwitchBoardRequestScheduler(int delay) + : base(delay) + { + } + + protected override int DequeueAndProcess(DateTime currentTime, TimeSpan span) + { + lock (syncObject) + { + Dictionary uniqueProcessors = new Dictionary(0); + + while (messageQueue.Count > 0 && currentTime - messageQueue.Peek().CreateTime >= span) + { + if (uniqueProcessors.ContainsKey(messageQueue.Peek().MessengerId)) + { + break; + } + else + { + + SchedulerQueueObject item = messageQueue.Dequeue(); + if (messengerList.ContainsKey(item.MessengerId) && messengerList[item.MessengerId].Connected) + { + try + { + item.MessageProcessor.SendMessage(item.Message); + uniqueProcessors.Add(item.MessengerId, item.MessageProcessor); + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, GetType().Name + " send bufferred message error: " + ex.Message); + } + } + } + } + + return messageQueue.Count; + } + } + } + + public static class Schedulers + { + private static Scheduler p2pInvitationScheduler = new Scheduler(5000); + private static Scheduler sbRequestScheduler = new SwitchBoardRequestScheduler(1000); + + public static Scheduler SwitchBoardRequestScheduler + { + get + { + return Schedulers.sbRequestScheduler; + } + } + + public static Scheduler P2PInvitationScheduler + { + get + { + return Schedulers.p2pInvitationScheduler; + } + } + } +} diff --git a/MSNPSharp/Services/ABServiceBindingWrapper.cs b/MSNPSharp/Services/ABServiceBindingWrapper.cs new file mode 100644 index 0000000..7905247 --- /dev/null +++ b/MSNPSharp/Services/ABServiceBindingWrapper.cs @@ -0,0 +1,72 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Sockets; + +namespace MSNPSharp.Services +{ + using MSNPSharp.MSNWS.MSNABSharingService; + + [System.Web.Services.WebServiceBindingAttribute(Name = "ABServiceBinding", Namespace = "http://www.msn.com/webservices/AddressBook")] + internal sealed class ABServiceBindingWrapper: ABServiceBinding + { + private IPEndPoint localEndPoint = null; + + public ABServiceBindingWrapper() + : base() + { + } + + public ABServiceBindingWrapper(IPEndPoint localEndPoint) + : base() + { + this.localEndPoint = localEndPoint; + } + + + protected override WebRequest GetWebRequest(Uri uri) + { + WebRequest request = base.GetWebRequest(uri); + if (request is HttpWebRequest) + { + (request as HttpWebRequest).ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint((new IPEndPointCallback(localEndPoint)).BindIPEndPointCallback); + } + + return request; + } + + } +} diff --git a/MSNPSharp/Services/ContactService.cs b/MSNPSharp/Services/ContactService.cs new file mode 100644 index 0000000..0e19f97 --- /dev/null +++ b/MSNPSharp/Services/ContactService.cs @@ -0,0 +1,3187 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Net; +using System.Xml; +using System.Text; +using System.Threading; +using System.Diagnostics; +using System.Globalization; +using System.Collections.Generic; +using System.Web.Services.Protocols; +using System.Text.RegularExpressions; + +namespace MSNPSharp +{ + using MSNPSharp.IO; + using MSNPSharp.Core; + using MSNPSharp.MSNWS.MSNABSharingService; + + /// + /// Provide webservice operations for contacts. This class cannot be inherited. + /// + public sealed class ContactService : MSNService + { + #region Fields + + private int recursiveCall; + private string applicationId = String.Empty; + private Dictionary initialADLs = new Dictionary(); + private bool abSynchronized; + private object syncObject = new object(); + + internal XMLContactList AddressBook; + internal DeltasList Deltas; + internal List pendingFQYs = new List(); + + #endregion + + public ContactService(NSMessageHandler nsHandler) + : base(nsHandler) + { + applicationId = nsHandler.Credentials.ClientInfo.ApplicationId; + + } + + #region Events + /// + /// Occurs when a contact is added to any list (including reverse list) + /// + public event EventHandler ContactAdded; + + /// + /// Occurs when a contact is removed from any list (including reverse list) + /// + public event EventHandler ContactRemoved; + + /// + /// Occurs when another user adds us to their contactlist. A ContactAdded event with the reverse list as parameter will also be raised. + /// + public event EventHandler ReverseAdded; + + /// + /// Occurs when another user removes us from their contactlist. A ContactRemoved event with the reverse list as parameter will also be raised. + /// + public event EventHandler ReverseRemoved; + + /// + /// Occurs when a new contactgroup is created + /// + public event EventHandler ContactGroupAdded; + + /// + /// Occurs when a contactgroup is removed + /// + public event EventHandler ContactGroupRemoved; + + /// + /// Occurs when a new is created. + /// + public event EventHandler CreateCircleCompleted; + + /// + /// Occurs when the owner has left a specific . + /// + public event EventHandler ExitCircleCompleted; + + /// + /// Occurs when a call to SynchronizeList() has been made and the synchronization process is completed. + /// This means all contact-updates are received from the server and processed. + /// + public event EventHandler SynchronizationCompleted; + + /// + /// Fired after the InviteContactToCircle succeeded. + /// + public event EventHandler InviteCircleMemberCompleted; + + /// + /// Fired after a circle member has left the circle. + /// + public event EventHandler CircleMemberLeft; + + /// + /// Fired after a circle member has joined the circle. + /// + public event EventHandler CircleMemberJoined; + + /// + /// Fired after a remote user invite us to join a circle. + /// + public event EventHandler JoinCircleInvitationReceived; + + /// + /// Fired after the owner join a circle successfully. + /// + public event EventHandler JoinedCircleCompleted; + #endregion + + #region Public members + + /// + /// Fires the event. + /// + /// + internal void OnReverseRemoved(ContactEventArgs e) + { + if (ReverseRemoved != null) + ReverseRemoved(this, e); + } + + /// + /// Fires the event. + /// + /// + internal void OnReverseAdded(ContactEventArgs e) + { + if (ReverseAdded != null) + ReverseAdded(this, e); + } + + /// + /// Fires the event. + /// + /// + internal void OnContactAdded(ListMutateEventArgs e) + { + if (ContactAdded != null) + { + ContactAdded(this, e); + } + } + + /// + /// Fires the event. + /// + /// + internal void OnContactRemoved(ListMutateEventArgs e) + { + if (ContactRemoved != null) + { + ContactRemoved(this, e); + } + } + + /// + /// Fires the event. + /// + /// + internal void OnContactGroupAdded(ContactGroupEventArgs e) + { + if (ContactGroupAdded != null) + { + ContactGroupAdded(this, e); + } + } + + /// + /// Fires the event. + /// + /// + internal void OnJoinCircleInvitationReceived(CircleEventArgs e) + { + //if (e.Inviter != null) + //{ + // Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + // e.Inviter.Name + "(" + e.Inviter.Account + ") invite you to join circle: " + // + e.Circle.ToString() + "\r\nMessage: " + e.Inviter.Message); + //} + + if (JoinCircleInvitationReceived != null) + { + JoinCircleInvitationReceived(this, e); + } + } + + /// + /// Fires the event. + /// + /// + internal void OnJoinedCircleCompleted(CircleEventArgs e) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Circle invitation accepted: " + e.Circle.ToString()); + + if (JoinedCircleCompleted != null) + { + JoinedCircleCompleted(this, e); + } + } + + /// + /// Fires the event. + /// + /// + internal void OnContactGroupRemoved(ContactGroupEventArgs e) + { + if (ContactGroupRemoved != null) + { + ContactGroupRemoved(this, e); + } + } + + + /// + /// Fires the event. + /// + /// + internal void OnCreateCircleCompleted(CircleEventArgs e) + { + if (CreateCircleCompleted != null) + { + CreateCircleCompleted(this, e); + } + } + + /// + /// Fires the event. + /// + /// + internal void OnExitCircleCompleted(CircleEventArgs e) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Exit circle completed: " + e.Circle.ToString()); + + if (ExitCircleCompleted != null) + { + ExitCircleCompleted(this, e); + } + } + + /// + /// Fires the event. + /// + /// + internal void OnCircleMemberLeft(CircleMemberEventArgs e) + { + if (CircleMemberLeft != null) + { + CircleMemberLeft(this, e); + } + } + + /// + /// Fires the event. + /// + /// + internal void OnCircleMemberJoined(CircleMemberEventArgs e) + { + if (CircleMemberJoined != null) + { + CircleMemberJoined(this, e); + } + } + + /// + /// Fires the event. + /// + /// + internal void OnSynchronizationCompleted(EventArgs e) + { + if (SynchronizationCompleted != null) + SynchronizationCompleted(this, e); + } + + /// + /// Fires the + /// + /// + private void OnInviteCircleMemberCompleted(CircleMemberEventArgs e) + { + if (InviteCircleMemberCompleted != null) + InviteCircleMemberCompleted(this, e); + } + + #endregion + + #region Properties + + public object SyncObject + { + get { return syncObject; } + } + + /// + /// Keep track whether a address book synchronization has been completed. + /// + public bool AddressBookSynchronized + { + get + { + return abSynchronized; + } + } + + #endregion + + #region Synchronize + + /// + /// Rebuild the contactlist with the most recent data. + /// + /// + /// Synchronizing is the most complete way to retrieve data about groups, contacts, privacy settings, etc. + /// This method is called automatically after owner profile received and then the addressbook is merged with deltas file. + /// After that, SignedIn event occurs and the client programmer must set it's initial status by SetPresenceStatus(). + /// Otherwise you won't receive online notifications from other clients or the connection is closed by the server. + /// If you have an external contact list, you must track ProfileReceived, SignedIn and SynchronizationCompleted events. + /// Between ProfileReceived and SignedIn: the internal addressbook is merged with deltas file. + /// Between SignedIn and SynchronizationCompleted: the internal addressbook is merged with most recent data by soap request. + /// All contact changes will be fired between ProfileReceived, SignedIn and SynchronizationCompleted events. + /// e.g: ContactAdded, ContactRemoved, ReverseAdded, ReverseRemoved. + /// + internal void SynchronizeContactList() + { + if (AddressBookSynchronized) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "SynchronizeContactList() was called, but the list has already been synchronized.", GetType().Name); + return; + } + + if (recursiveCall != 0) + { + DeleteRecordFile(); + } + + MclSerialization st = Settings.SerializationType; + string addressbookFile = Path.Combine(Settings.SavePath, NSMessageHandler.ContactList.Owner.Mail.GetHashCode() + ".mcl"); + string deltasResultsFile = Path.Combine(Settings.SavePath, NSMessageHandler.ContactList.Owner.Mail.GetHashCode() + "d" + ".mcl"); + + lock (SyncObject) + { + try + { + + AddressBook = XMLContactList.LoadFromFile(addressbookFile, st, NSMessageHandler, false); + Deltas = DeltasList.LoadFromFile(deltasResultsFile, st, NSMessageHandler, true); + + NSMessageHandler.MSNTicket.CacheKeys = Deltas.CacheKeys; + + if (NSMessageHandler.AutoSynchronize && + recursiveCall == 0 && + (AddressBook.Version != Properties.Resources.XMLContactListVersion || Deltas.Version != Properties.Resources.DeltasListVersion)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "AddressBook Version not match:\r\nMCL AddressBook Version: " + + AddressBook.Version.ToString() + "\r\nAddressBook Version Required:\r\nContactListVersion " + + Properties.Resources.XMLContactListVersion + ", DeltasList Version " + + Properties.Resources.DeltasListVersion + + "\r\nThe old mcl files for this account will be deleted and a new request for getting addressbook list will be post."); + + recursiveCall++; + SynchronizeContactList(); + return; + } + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "An error occured while getting addressbook: " + ex.Message + + "\r\nA new request for getting addressbook list will be post again.", GetType().Name); + + return; + } + + if (NSMessageHandler.AutoSynchronize && AddressBook != null) + { + try + { + AddressBook.Initialize(); + + if (WebServiceDateTimeConverter.ConvertToDateTime(AddressBook.GetAddressBookLastChange(WebServiceConstants.MessengerIndividualAddressBookId)) == DateTime.MinValue) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Getting your membership list for the first time. If you have a lot of contacts, please be patient!", GetType().Name); + } + msRequest( + PartnerScenario.Initial, + delegate + { + lock (SyncObject) + { + if (AddressBook != null && Deltas != null) + { + if (WebServiceDateTimeConverter.ConvertToDateTime(AddressBook.GetAddressBookLastChange(WebServiceConstants.MessengerIndividualAddressBookId)) == DateTime.MinValue) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Getting your address book for the first time. If you have a lot of contacts, please be patient!", GetType().Name); + } + + try{ + abRequest(PartnerScenario.Initial, + delegate + { + SetDefaults(); + } + ); + } + catch(Exception abRequestEception) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("ABFindContactsPaged", + new MSNPSharpException(abRequestEception.Message, abRequestEception))); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "An error occured while getting membership list: " + + abRequestEception.Message + + "\r\nA new request for getting addressbook list will be post again.", GetType().Name); + } + } + } + } + ); + } + catch (Exception ex) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("FindMembership", + new MSNPSharpException(ex.Message, ex))); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "An error occured while getting membership list: " + ex.Message + + "\r\nA new request for getting addressbook list will be post again.", GetType().Name); + } + } + else + { + // Set lastchanged and roaming profile last change to get display picture and personal message + NSMessageHandler.ContactService.AddressBook.MyProperties[AnnotationNames.Live_Profile_Expression_LastChanged] = XmlConvert.ToString(DateTime.MinValue, "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzzzzz"); + NSMessageHandler.ContactList.Owner.SetRoamLiveProperty(RoamLiveProperty.Enabled); + SetDefaults(); + NSMessageHandler.OnSignedIn(EventArgs.Empty); + } + } + } + + private void SetDefaults() + { + // Reset + recursiveCall = 0; + + lock (SyncObject) + { + if (NSMessageHandler.AutoSynchronize && AddressBook != null) + { + AddressBook.InitializeMyProperties(); + + // Set privacy settings and roam property + NSMessageHandler.ContactList.Owner.SetPrivacy((AddressBook.MyProperties[AnnotationNames.MSN_IM_BLP] == "1") ? PrivacyMode.AllExceptBlocked : PrivacyMode.NoneButAllowed); + NSMessageHandler.ContactList.Owner.SetNotifyPrivacy((AddressBook.MyProperties[AnnotationNames.MSN_IM_GTC] == "1") ? NotifyPrivacy.PromptOnAdd : NotifyPrivacy.AutomaticAdd); + NSMessageHandler.ContactList.Owner.SetRoamLiveProperty((AddressBook.MyProperties[AnnotationNames.MSN_IM_RoamLiveProperties] == "1") ? RoamLiveProperty.Enabled : RoamLiveProperty.Disabled); + NSMessageHandler.ContactList.Owner.SetMPOP((AddressBook.MyProperties[AnnotationNames.MSN_IM_MPOP] == "1") ? MPOP.KeepOnline : MPOP.AutoLogoff); + } + } + + OwnerProfile profileFromWeb = NSMessageHandler.StorageService.GetProfile(); + + if (profileFromWeb != null) + { + Deltas.Profile = profileFromWeb; + + // Set display name, personal status and photo + string mydispName = String.IsNullOrEmpty(Deltas.Profile.DisplayName) ? NSMessageHandler.ContactList.Owner.NickName : Deltas.Profile.DisplayName; + PersonalMessage pm = new PersonalMessage(Deltas.Profile.PersonalMessage, MediaType.None, null, NSMessageHandler.MachineGuid); + + NSMessageHandler.ContactList.Owner.SetName(mydispName); + NSMessageHandler.ContactList.Owner.SetPersonalMessage(pm); + NSMessageHandler.ContactList.Owner.CreateDefaultDisplayImage(Deltas.Profile.Photo.DisplayImage); + + if (NSMessageHandler.AutoSynchronize) + { + #region Initial ADL + + SendInitialADL(Scenario.SendInitialContactsADL | Scenario.SendInitialCirclesADL); + + #endregion + } + + // Save addressbook and then truncate deltas file. + lock (SyncObject) + { + if (AddressBook != null && Deltas != null) + { + AddressBook.Save(); + Deltas.Truncate(); + } + } + } + } + + /// + /// The indicator of whether the initial contact ADL has been processed.
+ /// If the contact ADL was not processed, ignore the circle ADL. + ///
+ bool contactADLProcessed = false; + Scenario ignoredSenario = Scenario.None; + + /// + /// Send the initial ADL command to NS server. + /// + /// + /// A + /// + /// + /// The first ADL command MUST be a contact ADL. If you send a circle ADL instead, + /// you will receive 201 server error for the following circle PUT command. + /// + internal void SendInitialADL(Scenario scene) + { + if (scene == Scenario.None) + return; + NSMessageProcessor nsmp = (NSMessageProcessor)NSMessageHandler.MessageProcessor; + + if (nsmp == null) + return; + + int firstADLKey = 0; + Dictionary hashlist = new Dictionary(); + + #region Process Contacts + + if ((scene & Scenario.SendInitialContactsADL) != Scenario.None) + { + // Combine initial ADL for Contacts + hashlist = new Dictionary(NSMessageHandler.ContactList.Count); + lock (NSMessageHandler.ContactList.SyncRoot) + { + foreach (Contact contact in NSMessageHandler.ContactList.All) + { + if (contact.ADLCount == 0) + continue; + + contact.ADLCount--; + + string ch = contact.Hash; + MSNLists l = MSNLists.None; + if (contact.IsMessengerUser) + l |= MSNLists.ForwardList; + if (contact.OnAllowedList) + l |= MSNLists.AllowedList; + else if (contact.OnBlockedList) + l |= MSNLists.BlockedList; + + if (l != MSNLists.None && !hashlist.ContainsKey(ch)) + hashlist.Add(ch, l); + } + } + string[] adls = ConstructLists(hashlist, true); + + if (adls.Length > 0) + { + foreach (string payload in adls) + { + NSPayLoadMessage message = new NSPayLoadMessage("ADL", payload); + message.TransactionID = nsmp.IncreaseTransactionID(); + initialADLs.Add(message.TransactionID, message); + + if (firstADLKey == 0) + { + firstADLKey = message.TransactionID; + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "#################### first contact ADL trasID: " + + firstADLKey + " ############################"); + } + } + } + contactADLProcessed = true; + scene |= ignoredSenario; + } + + #endregion + + #region Process Circles + + if ((scene & Scenario.SendInitialCirclesADL) != Scenario.None) + { + if(contactADLProcessed) + { + // Combine initial ADL for Circles + if (NSMessageHandler.CircleList.Count > 0) + { + hashlist = new Dictionary(NSMessageHandler.CircleList.Count); + lock (NSMessageHandler.CircleList.SyncRoot) + { + foreach (Circle circle in NSMessageHandler.CircleList) + { + if (circle.ADLCount == 0) + continue; + + circle.ADLCount--; + string ch = circle.Hash; + MSNLists l = circle.Lists; + hashlist.Add(ch, l); + } + } + + string[] circleadls = ConstructLists(hashlist, true); + + if (circleadls.Length > 0) + { + foreach (string payload in circleadls) + { + NSPayLoadMessage message = new NSPayLoadMessage("ADL", payload); + message.TransactionID = nsmp.IncreaseTransactionID(); + initialADLs.Add(message.TransactionID, message); + + if (firstADLKey == 0) + { + firstADLKey = message.TransactionID; + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "#################### first circle ADL trasID: " + + firstADLKey + " ############################"); + } + } + } + } + }else{ + ignoredSenario |= Scenario.SendInitialCirclesADL; + } + } + + #endregion + + // Send First Initial ADL,. + // NSHandler doesn't accept more than 3 ADLs at the same time... So we must wait OK response. + + if (initialADLs.ContainsKey(firstADLKey)) + { + NSPayLoadMessage firstADL = initialADLs[firstADLKey]; + nsmp.SendMessage(firstADL, firstADL.TransactionID); + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, + "#################### ADL trasID choosen: " + + firstADLKey + " ############################"); + } + } + + internal bool ProcessADL(int transid) + { + if (initialADLs.ContainsKey(transid)) + { + lock (this) + { + initialADLs.Remove(transid); + } + + if (initialADLs.Count <= 0) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "All initial ADLs have processed.", GetType().Name); + + if (NSMessageHandler.AutoSynchronize) + { + NSMessageHandler.OnSignedIn(EventArgs.Empty); + } + + if (!AddressBookSynchronized) + { + abSynchronized = true; + OnSynchronizationCompleted(EventArgs.Empty); + + if (NSMessageHandler.AutoSynchronize) + { + lock (NSMessageHandler.ContactList.SyncRoot) + { + foreach (Contact contact in NSMessageHandler.ContactList.All) + { + // Added by other place, this place hasn't synchronized this contact yet. + if (contact.OnForwardList && contact.OnPendingList) + { + contact.OnPendingList = false; + } + // At this phase, we requested all memberships including pending. + else if (contact.OnPendingList || + (contact.OnReverseList && !contact.OnAllowedList && !contact.OnBlockedList)) + { + NSMessageHandler.ContactService.OnReverseAdded(new ContactEventArgs(contact)); + } + } + + } + } + } + } + else + { + // Send next ADL... + foreach (NSPayLoadMessage nsPayload in initialADLs.Values) + { + ((NSMessageProcessor)NSMessageHandler.MessageProcessor).SendMessage(nsPayload, nsPayload.TransactionID); + break; + } + } + return true; + } + return false; + } + + /// + /// Async membership request + /// + /// + /// The delegate to be executed after async membership request completed successfuly + internal void msRequest(PartnerScenario partnerScenario, FindMembershipCompletedEventHandler onSuccess) + { + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("FindMembership", new MSNPSharpException("You don't have access right on this action anymore."))); + } + else + { + bool msdeltasOnly = false; + DateTime serviceLastChange = WebServiceDateTimeConverter.ConvertToDateTime(WebServiceConstants.ZeroTime); + DateTime msLastChange = WebServiceDateTimeConverter.ConvertToDateTime(AddressBook.MembershipLastChange); + + string strLastChange = WebServiceConstants.ZeroTime; + + if (msLastChange != serviceLastChange && recursiveCall == 0) + { + msdeltasOnly = true; + + strLastChange = AddressBook.MembershipLastChange; + } + + MsnServiceState FindMembershipObject = new MsnServiceState(partnerScenario, "FindMembership", true); + SharingServiceBinding sharingService = (SharingServiceBinding)CreateService(MsnServiceType.Sharing, FindMembershipObject); + FindMembershipRequestType request = new FindMembershipRequestType(); + request.View = "Full"; // NO default! + request.deltasOnly = msdeltasOnly; + request.lastChange = strLastChange; + request.serviceFilter = new FindMembershipRequestTypeServiceFilter(); + request.serviceFilter.Types = new string[] + { + ServiceFilterType.Messenger/*, + ServiceFilterType.Invitation, + ServiceFilterType.SocialNetwork, + ServiceFilterType.Profile, + ServiceFilterType.Folder, + ServiceFilterType.OfficeLiveWebNotification*/ + }; + + sharingService.FindMembershipCompleted += delegate(object sender, FindMembershipCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(sharingService, MsnServiceType.Sharing, e)); + + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled) + { + if (e.Error != null) + { + lock (SyncObject) + { + if (AddressBook == null && Deltas == null && AddressBookSynchronized == false) + { + // This means before the webservice returned the connection had broken. + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("FindMembership", + new MSNPSharpException("Addressbook and Deltas have been reset."))); + return; + } + if (e.Error.Message.Contains("Address Book Does Not Exist")) + { + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("FindMembership", new MSNPSharpException("You don't have access right on this action anymore."))); + } + else + { + MsnServiceState ABAddObject = new MsnServiceState(partnerScenario, "ABAdd", true); + ABServiceBinding abservice = (ABServiceBinding)CreateService(MsnServiceType.AB, ABAddObject); + abservice.ABAddCompleted += delegate(object srv, ABAddCompletedEventArgs abadd_e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abservice, MsnServiceType.AB, abadd_e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (abadd_e.Error == null) + { + try + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "A new addressbook has been added, addressbook list will be request again."); + recursiveCall++; + SynchronizeContactList(); + } + catch (Exception unknownSyncException) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("FindMembership", + new MSNPSharpException("Unknown Exception occurred while synchronizing contact list, please see inner exception.", + unknownSyncException))); + } + } + }; + ABAddRequestType abAddRequest = new ABAddRequestType(); + abAddRequest.abInfo = new abInfoType(); + abAddRequest.abInfo.ownerEmail = NSMessageHandler.ContactList.Owner.Mail; + abAddRequest.abInfo.ownerPuid = "0"; + abAddRequest.abInfo.fDefault = true; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abservice, MsnServiceType.AB, ABAddObject, abAddRequest)); + } + } + else if ((recursiveCall == 0 && partnerScenario == PartnerScenario.Initial) + || (e.Error.Message.Contains("Full sync required"))) + { + try + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "Need to do full sync of current addressbook list, addressbook list will be request again. Method: FindMemberShip"); + recursiveCall++; + SynchronizeContactList(); + } + catch (Exception unknownSyncException) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("FindMembership", + new MSNPSharpException("Unknown Exception occurred while synchronizing contact list, please see inner exception.", + unknownSyncException))); + } + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, e.Error.ToString(), GetType().Name); + } + } + } + else + { + lock (SyncObject) + { + if (null != e.Result.FindMembershipResult && AddressBook != null) + { + try + { + XMLContactList addressbook = AddressBook.Merge(e.Result.FindMembershipResult); + addressbook.Save(); + } + catch (Exception unknownException) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("FindMembership", + new MSNPSharpException("Unknown Exception occurred while synchronizing contact list, please see inner exception.", + unknownException))); + } + + } + + if (AddressBook != null && Deltas != null) + { + if (onSuccess != null) + { + onSuccess(sharingService, e); + } + } + else + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("FindMembership", + new MSNPSharpException("Addressbook and Deltas have been reset."))); + } + } + } + } + }; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(sharingService, MsnServiceType.Sharing, FindMembershipObject, request)); + } + } + + /// + /// Async Address book request + /// + /// + /// The delegate to be executed after async ab request completed successfuly + internal void abRequest(PartnerScenario partnerScenario, ABFindContactsPagedCompletedEventHandler onSuccess) + { + try + { + abRequest(partnerScenario, null, onSuccess); + }catch(Exception ex) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("ABFindContactsPaged", + new MSNPSharpException(ex.Message, ex))); + } + } + + /// + /// Async Address book request + /// + /// + /// The specified addressbook to retrieve. + /// The delegate to be executed after async ab request completed successfuly + /// This function does not handle any error, must put try/catch block around this method. + internal void abRequest(PartnerScenario partnerScenario, abHandleType abHandle, ABFindContactsPagedCompletedEventHandler onSuccess) + { + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("ABFindContactsPaged", new MSNPSharpException("You don't have access right on this action anymore."))); + } + else + { + bool deltasOnly = false; + + MsnServiceState ABFindContactsPagedObject = new MsnServiceState(partnerScenario, "ABFindContactsPaged", true); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, ABFindContactsPagedObject); + ABFindContactsPagedRequestType request = new ABFindContactsPagedRequestType(); + request.abView = "MessengerClient8"; //NO default! + + if (abHandle == null || abHandle.ABId == WebServiceConstants.MessengerIndividualAddressBookId) + { + request.extendedContent = "AB AllGroups CircleResult"; + + request.filterOptions = new filterOptionsType(); + request.filterOptions.ContactFilter = new ContactFilterType(); + + if (WebServiceDateTimeConverter.ConvertToDateTime(AddressBook.GetAddressBookLastChange(WebServiceConstants.MessengerIndividualAddressBookId)) != DateTime.MinValue) + { + deltasOnly = true; + request.filterOptions.LastChanged = AddressBook.GetAddressBookLastChange(WebServiceConstants.MessengerIndividualAddressBookId); + } + + request.filterOptions.DeltasOnly = deltasOnly; + request.filterOptions.ContactFilter.IncludeHiddenContacts = true; + } + else + { + request.extendedContent = "AB"; + request.abHandle = abHandle; + } + + abService.ABFindContactsPagedCompleted += delegate(object sender, ABFindContactsPagedCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abService, MsnServiceType.AB, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled) + { + if (e.Error != null) + { + lock (SyncObject) + { + if (AddressBook == null && Deltas == null && AddressBookSynchronized == false) + { + // This means before the webservice returned the connection had broken. + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("ABFindContactsPaged", + new MSNPSharpException("Addressbook and Deltas have been reset."))); + return; + } + + if ((recursiveCall == 0 && ((MsnServiceState)e.UserState).PartnerScenario == PartnerScenario.Initial + && (abHandle == null || abHandle.ABId == WebServiceConstants.MessengerIndividualAddressBookId)) + || (e.Error.Message.Contains("Need to do full sync") || e.Error.Message.Contains("Full sync required"))) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "Need to do full sync of current addressbook list, addressbook list will be request again. Method: ABFindContactsPaged"); + + recursiveCall++; + + AddressBook.ClearCircleInfos(); + try + { + SynchronizeContactList(); + } + catch (Exception ex) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("ABFindContactsPaged", + new MSNPSharpException("Unknown Exception occurred while synchronizing contact list, please see inner exception.", + ex))); + } + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, e.Error.ToString(), GetType().Name); + } + } + } + else + { + lock (SyncObject) + { + if (null != e.Result.ABFindContactsPagedResult && AddressBook != null) + { + + string lowerId = WebServiceConstants.MessengerIndividualAddressBookId; + + if (e.Result.ABFindContactsPagedResult.Ab != null) + lowerId = e.Result.ABFindContactsPagedResult.Ab.abId.ToLowerInvariant(); + + if (lowerId == WebServiceConstants.MessengerIndividualAddressBookId) + { + AddressBook.MergeIndividualAddressBook(e.Result.ABFindContactsPagedResult); + } + else + { + AddressBook.MergeGroupAddressBook(e.Result.ABFindContactsPagedResult); + } + + AddressBook.Save(); + } + + if (e.Result.ABFindContactsPagedResult.CircleResult != null) + NSMessageHandler.SendSHAAMessage(e.Result.ABFindContactsPagedResult.CircleResult.CircleTicket); + + + if (AddressBook != null && Deltas != null) + { + if (onSuccess != null) + { + onSuccess(abService, e); + } + } + else + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("ABFindContactsPaged", + new MSNPSharpException("Addressbook and Deltas have been reset."))); + } + + } + } + } + }; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abService, MsnServiceType.AB, ABFindContactsPagedObject, request)); + } + } + + public static string[] ConstructLists(Dictionary contacts, bool initial) + { + + List mls = new List(); + XmlDocument xmlDoc = new XmlDocument(); + XmlElement mlElement = xmlDoc.CreateElement("ml"); + if (initial) + mlElement.SetAttribute("l", "1"); + + if (contacts == null || contacts.Count == 0) + { + mls.Add(mlElement.OuterXml); + return mls.ToArray(); + } + + List sortedContacts = new List(contacts.Keys); + sortedContacts.Sort(CompareContactsHash); + + int domaincontactcount = 0; + string currentDomain = null; + XmlElement domtelElement = null; + + foreach (string contact_hash in sortedContacts) + { + String name; + String domain; + string[] arr = contact_hash.Split(new string[] { ":", ";via=" }, StringSplitOptions.RemoveEmptyEntries); + MSNLists sendlist = contacts[contact_hash]; + String type = ClientType.EmailMember.ToString(); + + if (arr.Length > 0) + type = arr[0]; + + ClientType clitype = (ClientType)Enum.Parse(typeof(ClientType), type); + type = ((int)clitype).ToString(); + + if (clitype == ClientType.PhoneMember) + { + if (!arr[1].StartsWith("+")) + continue; + + domain = String.Empty; + name = "tel:" + arr[1]; + } + else + { + String[] usernameanddomain = arr[1].Split('@'); + domain = usernameanddomain[1]; + name = usernameanddomain[0]; + } + + if (sendlist != MSNLists.None) + { + if (currentDomain != domain) + { + currentDomain = domain; + domaincontactcount = 0; + + if (clitype == ClientType.PhoneMember) + { + domtelElement = xmlDoc.CreateElement("t"); + } + else + { + domtelElement = xmlDoc.CreateElement("d"); + domtelElement.SetAttribute("n", currentDomain); + } + mlElement.AppendChild(domtelElement); + } + + XmlElement contactElement = xmlDoc.CreateElement("c"); + contactElement.SetAttribute("n", name); + contactElement.SetAttribute("l", ((int)sendlist).ToString()); + if (clitype != ClientType.PhoneMember) + { + contactElement.SetAttribute("t", type); + } + domtelElement.AppendChild(contactElement); + domaincontactcount++; + } + + if (mlElement.OuterXml.Length > 7300) + { + mlElement.AppendChild(domtelElement); + mls.Add(mlElement.OuterXml); + + mlElement = xmlDoc.CreateElement("ml"); + if (initial) + mlElement.SetAttribute("l", "1"); + + currentDomain = null; + domaincontactcount = 0; + } + } + + if (domaincontactcount > 0 && domtelElement != null) + mlElement.AppendChild(domtelElement); + + mls.Add(mlElement.OuterXml); + return mls.ToArray(); + } + + private static int CompareContactsHash(string hash1, string hash2) + { + string[] str_arr1 = hash1.Split(new string[] { ":", ";via=" }, StringSplitOptions.RemoveEmptyEntries); + string[] str_arr2 = hash2.Split(new string[] { ":", ";via=" }, StringSplitOptions.RemoveEmptyEntries); + + if (str_arr1.Length == 0) + return 1; + + else if (str_arr2.Length == 0) + return -1; + + string xContact, yContact; + + if (str_arr1[1].IndexOf("@") == -1) + xContact = str_arr1[1]; + else + xContact = str_arr1[1].Substring(str_arr1[1].IndexOf("@") + 1); + + if (str_arr2[1].IndexOf("@") == -1) + yContact = str_arr2[1]; + else + yContact = str_arr2[1].Substring(str_arr2[1].IndexOf("@") + 1); + + return String.Compare(xContact, yContact, true, CultureInfo.InvariantCulture); + } + + #endregion + + #region Contact & Group Operations + + #region Add Contact + + private void AddNonPendingContact(string account, ClientType ct, string invitation, string otheremail) + { + // Query other networks and add as new contact if available + if (account.Contains("@") && ct == ClientType.PassportMember) + { + string federatedQuery = ""; + federatedQuery = federatedQuery.Replace("{d}", account.Split('@')[1]); + federatedQuery = federatedQuery.Replace("{n}", account.Split('@')[0]); + + NSMessageProcessor nsmp = (NSMessageProcessor)NSMessageHandler.MessageProcessor; + NSPayLoadMessage message = new NSPayLoadMessage("FQY", federatedQuery); + message.TransactionID = nsmp.IncreaseTransactionID(); + pendingFQYs.Add(message.TransactionID); + nsmp.SendMessage(message, message.TransactionID); + } + + // Add contact to address book with "ContactSave" + AddNewOrPendingContact( + account, + false, + invitation, + ct, + otheremail, + delegate(object service, ABContactAddCompletedEventArgs e) + { + Contact contact = NSMessageHandler.ContactList.GetContact(account, ct); + contact.Guid = new Guid(e.Result.ABContactAddResult.guid); + + if (!contact.OnBlockedList) + { + // Add to AL + if (ct == ClientType.PassportMember) + { + // without membership, contact service adds this contact to AL automatically. + Dictionary hashlist = new Dictionary(2); + hashlist.Add(contact.Hash, MSNLists.AllowedList); + string payload = ConstructLists(hashlist, false)[0]; + NSMessageHandler.MessageProcessor.SendMessage(new NSPayLoadMessage("ADL", payload)); + contact.AddToList(MSNLists.AllowedList); + } + else + { + // with membership + contact.OnAllowedList = true; + } + } + + // Add to Forward List + contact.OnForwardList = true; + + // Get all information. LivePending will be Live :) + abRequest(PartnerScenario.ContactSave, null); + } + ); + } + + private void AddPendingContact(Contact contact) + { + // Delete PL with "ContactMsgrAPI" + RemoveContactFromList(contact, MSNLists.PendingList, null); + + // ADD contact to AB with "ContactMsgrAPI" + AddNewOrPendingContact( + contact.Mail, + true, + String.Empty, + contact.ClientType, + String.Empty, + delegate(object service, ABContactAddCompletedEventArgs e) + { + contact.Guid = new Guid(e.Result.ABContactAddResult.guid); + + // FL + contact.OnForwardList = true; + + // Add RL membership with "ContactMsgrAPI" + AddContactToList(contact, + MSNLists.ReverseList, + delegate + { + if (!contact.OnBlockedList) + { + // AL: Extra work for EmailMember: Add allow membership + if (ClientType.EmailMember == contact.ClientType) + { + contact.OnAllowedList = true; + } + else + { + // without membership, contact service adds this contact to AL automatically. + Dictionary hashlist = new Dictionary(0); + hashlist.Add(contact.Hash, Contact.GetListForADL(contact.Lists) | MSNLists.AllowedList); //you MUST put forward list here or other contact can't see you. + string payload = ConstructLists(hashlist, false)[0]; + NSMessageHandler.MessageProcessor.SendMessage(new NSPayLoadMessage("ADL", payload)); + contact.AddToList(MSNLists.AllowedList); + } + } + + abRequest(PartnerScenario.ContactMsgrAPI, null); + } + ); + } + ); + } + + private void FindContactsByContactIds(List contactIds, Guid abId, ABFindByContactsCompletedEventHandler onSuccess) + { + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("ABFindByContacts", new MSNPSharpException("You don't have access right on this action anymore."))); + } + else + { + MsnServiceState ABFindByContactsObject = new MsnServiceState(PartnerScenario.ContactMsgrAPI, "ABFindByContacts", true); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, ABFindByContactsObject); + abService.ABFindByContactsCompleted += delegate(object service, ABFindByContactsCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abService, MsnServiceType.AB, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled && e.Error == null) + { + if (onSuccess != null) + { + onSuccess(service, e); + } + } + }; + + ABFindByContactsRequestType request = new ABFindByContactsRequestType(); + request.abId = abId.ToString("D").ToLowerInvariant(); + List stringContactIds = new List(0); + + foreach (Guid contactId in contactIds) + { + stringContactIds.Add(contactId.ToString("D").ToLowerInvariant()); + } + + request.contactIds = stringContactIds.ToArray(); + request.abView = "Full"; + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abService, MsnServiceType.AB, ABFindByContactsObject, request)); + } + } + + private Guid GetConflictObjectId(string xmlErrorMessage) + { + Match match = Regex.Match(xmlErrorMessage, @"([A-Za-z0-9\-]+)", RegexOptions.IgnoreCase); + if (match.Success) + return new Guid(match.Groups[1].Value); + return Guid.Empty; + } + + internal class FakeABContactAddCompletedEventArgs : ABContactAddCompletedEventArgs + { + public FakeABContactAddCompletedEventArgs(ABContactAddResponse response) + : base(new object[] { response }, null, false, null) + { + + } + } + + private void AddNewOrPendingContact(string account, bool pending, string invitation, ClientType network, string otheremail, ABContactAddCompletedEventHandler onSuccess) + { + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("AddContact", new MSNPSharpException("You don't have access right on this action anymore."))); + } + else + { + MsnServiceState ABContactAddObject = new MsnServiceState(pending ? PartnerScenario.ContactMsgrAPI : PartnerScenario.ContactSave, "ABContactAdd", true); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, ABContactAddObject); + abService.ABContactAddCompleted += delegate(object service, ABContactAddCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abService, MsnServiceType.AB, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled && e.Error == null) + { + if (onSuccess != null) + { + onSuccess(service, e); + } + } + else + { + if ((e.Error.Message.Contains("Hidden Contact with Same PUID Already Exists") || + e.Error.Message.Contains("Contact Already Exists")) + && e.Error is SoapException) + { + SoapException soapException = e.Error as SoapException; + Guid conflictContactId = GetConflictObjectId(soapException.Detail.InnerXml); + if (conflictContactId == Guid.Empty) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "Cannot get conflict object Id from :\r\n " + + e.Error.Message + "\r\n" + + "Add new contact :" + account + " failed."); + return; + } + + + //Retrieve the hidden contact. + FindContactsByContactIds(new List(new Guid[] { conflictContactId }), + new Guid(WebServiceConstants.MessengerIndividualAddressBookId), + //Update the hidden contact to a messenger contact. + delegate(object s, ABFindByContactsCompletedEventArgs result) + { + if (result.Result.ABFindByContactsResult.contacts.Length == 0) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, + "AddNewOrPendingContact cannot retrieve contact by contactId: " + + conflictContactId.ToString("D")); + return; + } + + ContactType contactRetrieved = result.Result.ABFindByContactsResult.contacts[0]; + ContactType contactToChange = new ContactType(); + contactToChange.contactId = conflictContactId.ToString("D").ToLowerInvariant(); + contactToChange.contactInfo = new contactInfoType(); + contactToChange.contactInfo.passportName = contactRetrieved.contactInfo.passportName; + contactToChange.contactInfo.isMessengerUser = true; + contactToChange.contactInfo.isMessengerUserSpecified = true; + + contactToChange.contactInfo.MessengerMemberInfo = new MessengerMemberInfo(); + contactToChange.contactInfo.MessengerMemberInfo.DisplayName = contactRetrieved.contactInfo.displayName; + + contactToChange.propertiesChanged = "IsMessengerUser MessengerMemberInfo"; + UpdateContact(contactToChange, WebServiceConstants.MessengerIndividualAddressBookId, + delegate + { + if (onSuccess != null) + { + ABContactAddResponse fakeResponse = new ABContactAddResponse(); + fakeResponse.ABContactAddResult = new ABContactAddResultType(); + fakeResponse.ABContactAddResult.guid = conflictContactId.ToString("D").ToLowerInvariant(); + FakeABContactAddCompletedEventArgs fakeArgs = new FakeABContactAddCompletedEventArgs(fakeResponse); + + onSuccess(service, fakeArgs); + } + }); + } + ); + } + + } + }; + + ABContactAddRequestType request = new ABContactAddRequestType(); + request.abId = WebServiceConstants.MessengerIndividualAddressBookId; + request.contacts = new ContactType[] { new ContactType() }; + request.contacts[0].contactInfo = new contactInfoType(); + + switch (network) + { + case ClientType.PassportMember: + request.contacts[0].contactInfo.contactType = MessengerContactType.Regular; // MUST BE "Regular". See r746 + request.contacts[0].contactInfo.passportName = account; + request.contacts[0].contactInfo.isMessengerUser = true; + request.contacts[0].contactInfo.isMessengerUserSpecified = true; + request.contacts[0].contactInfo.MessengerMemberInfo = new MessengerMemberInfo(); + if (pending == false && !String.IsNullOrEmpty(invitation)) + { + request.contacts[0].contactInfo.MessengerMemberInfo.PendingAnnotations = new Annotation[] { new Annotation() }; + request.contacts[0].contactInfo.MessengerMemberInfo.PendingAnnotations[0].Name = AnnotationNames.MSN_IM_InviteMessage; + request.contacts[0].contactInfo.MessengerMemberInfo.PendingAnnotations[0].Value = invitation; + } + request.contacts[0].contactInfo.MessengerMemberInfo.DisplayName = NSMessageHandler.ContactList.Owner.Name; + request.options = new ABContactAddRequestTypeOptions(); + request.options.EnableAllowListManagement = true; //contact service adds this contact to AL automatically if not blocked. + break; + + case ClientType.EmailMember: + + List emails = new List(); + + if (!String.IsNullOrEmpty(otheremail)) + { + contactEmailType email1 = new contactEmailType(); + email1.contactEmailType1 = ContactEmailTypeType.ContactEmailOther; + email1.email = otheremail; + email1.propertiesChanged = PropertyString.Email; + emails.Add(email1); + } + + contactEmailType emailYahoo = new contactEmailType(); + emailYahoo.contactEmailType1 = ContactEmailTypeType.Messenger2; + emailYahoo.email = account; + emailYahoo.isMessengerEnabled = true; + emailYahoo.Capability = ((int)network).ToString(); + emailYahoo.propertiesChanged = String.Join(PropertyString.propertySeparator, + new string[] { PropertyString.Email, PropertyString.IsMessengerEnabled, PropertyString.Capability }); + + emails.Add(emailYahoo); + request.contacts[0].contactInfo.emails = emails.ToArray(); + break; + + case ClientType.PhoneMember: + request.contacts[0].contactInfo.phones = new contactPhoneType[] { new contactPhoneType() }; + request.contacts[0].contactInfo.phones[0].contactPhoneType1 = ContactPhoneTypes.ContactPhoneMobile; + request.contacts[0].contactInfo.phones[0].number = account; + request.contacts[0].contactInfo.phones[0].isMessengerEnabled = true; + request.contacts[0].contactInfo.phones[0].propertiesChanged = + String.Join(PropertyString.propertySeparator, + new string[] { PropertyString.Number, PropertyString.IsMessengerEnabled }); + break; + } + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abService, MsnServiceType.AB, ABContactAddObject, request)); + } + } + + /// + /// Creates a new contact on your address book and adds to allowed list if not blocked before. + /// + /// An email address or phone number to add. The email address can be yahoo account. + /// The phone format is +CC1234567890 for phone contact, CC is Country Code + public void AddNewContact(string account) + { + AddNewContact(account, String.Empty); + } + + /// + /// Creates a new contact on your address book and adds to allowed list if not blocked before. + /// + /// An email address or phone number to add. The email address can be yahoo account. + /// The reason of the adding contact + /// The phone format is +CC1234567890, CC is Country Code + public void AddNewContact(string account, string invitation) + { + long test; + if (long.TryParse(account, out test) || + (account.StartsWith("+") && long.TryParse(account.Substring(1), out test))) + { + if (account.StartsWith("00")) + { + account = "+" + account.Substring(2); + } + AddNewContact(account, ClientType.PhoneMember, invitation, String.Empty); + } + else + { + AddNewContact(account, ClientType.PassportMember, invitation, String.Empty); + } + } + + internal void AddNewContact(string account, ClientType network, string invitation, string otheremail) + { + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("AddContact", new MSNPSharpException("You don't have access right on this action anymore."))); + return; + } + + if (NSMessageHandler.ContactList.HasContact(account, network)) + { + Contact contact = NSMessageHandler.ContactList.GetContact(account, network); + + if (contact.OnPendingList) + { + AddPendingContact(contact); + } + else if (contact.Guid == Guid.Empty) // This user is on AL or BL or RL. + { + AddNonPendingContact(account, network, invitation, otheremail); + } + else if (contact.Guid != Guid.Empty) // Email or Messenger buddy. + { + if (!contact.IsMessengerUser) // Email buddy, make Messenger :) + { + contact.IsMessengerUser = true; + } + if (!contact.OnBlockedList) // Messenger buddy. Not in AL. + { + contact.OnAllowedList = true; + } + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Cannot add contact: " + contact.Hash, GetType().Name); + } + } + else + { + AddNonPendingContact(account, network, invitation, otheremail); + } + } + + #endregion + + #region RemoveContact + + /// + /// Remove the specified contact from your forward list. + /// Note that remote contacts that are allowed/blocked remain allowed/blocked. + /// + /// Contact to remove + public void RemoveContact(Contact contact) + { + if (contact.Guid == null || contact.Guid == Guid.Empty) + throw new InvalidOperationException("This is not a valid Messenger contact."); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("ABContactDelete", new MSNPSharpException("You don't have access right on this action anymore."))); + return; + } + + MsnServiceState ABContactDeleteObject = new MsnServiceState(PartnerScenario.Timer, "ABContactDelete", true); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, ABContactDeleteObject); + abService.ABContactDeleteCompleted += delegate(object service, ABContactDeleteCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abService, MsnServiceType.AB, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled && e.Error == null) + { + abRequest(PartnerScenario.ContactSave, + delegate + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Delete contact :" + contact.Hash + " completed."); + } + ); + } + }; + + ABContactDeleteRequestType request = new ABContactDeleteRequestType(); + request.abId = WebServiceConstants.MessengerIndividualAddressBookId; + request.contacts = new ContactIdType[] { new ContactIdType() }; + request.contacts[0].contactId = contact.Guid.ToString(); + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abService, MsnServiceType.AB, ABContactDeleteObject, request)); + } + + #endregion + + #region UpdateContact + + internal void UpdateContact(Contact contact, Guid abId, ABContactUpdateCompletedEventHandler onSuccess) + { + UpdateContact(contact, abId.ToString("D"), onSuccess); + } + + internal void UpdateContact(Contact contact, string abId, ABContactUpdateCompletedEventHandler onSuccess) + { + string lowerId = abId.ToLowerInvariant(); + + if (contact.Guid == null || contact.Guid == Guid.Empty) + throw new InvalidOperationException("This is not a valid Messenger contact."); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("ABContactUpdate", new MSNPSharpException("You don't have access right on this action anymore."))); + return; + } + + if (!AddressBook.HasContact(lowerId, contact.Guid)) + return; + + ContactType abContactType = AddressBook.SelectContactFromAddressBook(lowerId, contact.Guid); + ContactType contactToChange = new ContactType(); + + List propertiesChanged = new List(); + + contactToChange.contactId = contact.Guid.ToString(); + contactToChange.contactInfo = new contactInfoType(); + + // Comment + if (abContactType.contactInfo.comment != contact.Comment) + { + propertiesChanged.Add(PropertyString.Comment); + contactToChange.contactInfo.comment = contact.Comment; + } + + // DisplayName + if (abContactType.contactInfo.displayName != contact.Name) + { + propertiesChanged.Add(PropertyString.DisplayName); + contactToChange.contactInfo.displayName = contact.Name; + } + + //HasSpace + if (abContactType.contactInfo.hasSpace != contact.HasSpace && abContactType.contactInfo.hasSpaceSpecified) + { + propertiesChanged.Add(PropertyString.HasSpace); + contactToChange.contactInfo.hasSpace = contact.HasSpace; + } + + // Annotations + List annotationsChanged = new List(); + Dictionary oldAnnotations = new Dictionary(); + if (abContactType.contactInfo.annotations != null) + { + foreach (Annotation anno in abContactType.contactInfo.annotations) + { + oldAnnotations[anno.Name] = anno.Value; + } + } + + // Annotations: AB.NickName + string oldNickName = oldAnnotations.ContainsKey(AnnotationNames.AB_NickName) ? oldAnnotations[AnnotationNames.AB_NickName] : String.Empty; + if (oldNickName != contact.NickName) + { + Annotation anno = new Annotation(); + anno.Name = AnnotationNames.AB_NickName; + anno.Value = contact.NickName; + annotationsChanged.Add(anno); + } + + if (annotationsChanged.Count > 0) + { + propertiesChanged.Add(PropertyString.Annotation); + contactToChange.contactInfo.annotations = annotationsChanged.ToArray(); + } + + + // ClientType changes + switch (contact.ClientType) + { + case ClientType.PassportMember: + { + // IsMessengerUser + if (abContactType.contactInfo.isMessengerUser != contact.IsMessengerUser) + { + propertiesChanged.Add(PropertyString.IsMessengerUser); + contactToChange.contactInfo.isMessengerUser = contact.IsMessengerUser; + contactToChange.contactInfo.isMessengerUserSpecified = true; + propertiesChanged.Add(PropertyString.MessengerMemberInfo); // Pang found WLM2009 add this. + contactToChange.contactInfo.MessengerMemberInfo = new MessengerMemberInfo(); // But forgot to add this... + contactToChange.contactInfo.MessengerMemberInfo.DisplayName = NSMessageHandler.ContactList.Owner.Name; // and also this :) + } + + // ContactType + if (abContactType.contactInfo.contactType != contact.ContactType) + { + propertiesChanged.Add(PropertyString.ContactType); + contactToChange.contactInfo.contactType = contact.ContactType; + } + } + break; + + case ClientType.EmailMember: + { + if (abContactType.contactInfo.emails != null) + { + foreach (contactEmailType em in abContactType.contactInfo.emails) + { + if (em.email.ToLowerInvariant() == contact.Mail.ToLowerInvariant() && em.isMessengerEnabled != contact.IsMessengerUser) + { + propertiesChanged.Add(PropertyString.ContactEmail); + contactToChange.contactInfo.emails = new contactEmailType[] { new contactEmailType() }; + contactToChange.contactInfo.emails[0].contactEmailType1 = ContactEmailTypeType.Messenger2; + contactToChange.contactInfo.emails[0].isMessengerEnabled = contact.IsMessengerUser; + contactToChange.contactInfo.emails[0].propertiesChanged = PropertyString.IsMessengerEnabled; //"IsMessengerEnabled"; + break; + } + } + } + } + break; + + case ClientType.PhoneMember: + { + if (abContactType.contactInfo.phones != null) + { + foreach (contactPhoneType ph in abContactType.contactInfo.phones) + { + if (ph.number == contact.Mail && ph.isMessengerEnabled != contact.IsMessengerUser) + { + propertiesChanged.Add(PropertyString.ContactPhone); + contactToChange.contactInfo.phones = new contactPhoneType[] { new contactPhoneType() }; + contactToChange.contactInfo.phones[0].contactPhoneType1 = ContactPhoneTypes.ContactPhoneMobile; + contactToChange.contactInfo.phones[0].isMessengerEnabled = contact.IsMessengerUser; + contactToChange.contactInfo.phones[0].propertiesChanged = PropertyString.IsMessengerEnabled; //"IsMessengerEnabled"; + break; + } + } + } + } + break; + } + + if (propertiesChanged.Count > 0) + { + contactToChange.propertiesChanged = String.Join(PropertyString.propertySeparator, propertiesChanged.ToArray()); + UpdateContact(contactToChange, WebServiceConstants.MessengerIndividualAddressBookId, onSuccess); + } + } + + private void UpdateContact(ContactType contact, string abId, ABContactUpdateCompletedEventHandler onSuccess) + { + ABContactUpdateRequestType request = new ABContactUpdateRequestType(); + request.abId = abId; + request.contacts = new ContactType[] { contact }; + request.options = new ABContactUpdateRequestTypeOptions(); + request.options.EnableAllowListManagementSpecified = true; + request.options.EnableAllowListManagement = true; + + MsnServiceState ABContactUpdateObject = new MsnServiceState(contact.contactInfo.isMessengerUser ? PartnerScenario.ContactSave : PartnerScenario.Timer, "ABContactUpdate", true); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, ABContactUpdateObject); + abService.ABContactUpdateCompleted += delegate(object service, ABContactUpdateCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abService, MsnServiceType.AB, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled && e.Error == null) + { + abRequest(PartnerScenario.ContactSave, delegate + { + if (onSuccess != null) + onSuccess(service, e); + } + ); + } + }; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abService, MsnServiceType.AB, ABContactUpdateObject, request)); + + } + + internal void UpdateMe() + { + if (NSMessageHandler.AutoSynchronize) + { + AddressBook.InitializeMyProperties(); + + UpdatePrivacySettings(); + UpdateGeneralDialogSettings(); + } + } + + private void UpdateGeneralDialogSettings() + { + Owner owner = NSMessageHandler.ContactList.Owner; + + if (owner == null) + throw new InvalidOperationException("This is not a valid Messenger contact."); + + MPOP oldMPOP = AddressBook.MyProperties[AnnotationNames.MSN_IM_MPOP] == "1" ? MPOP.KeepOnline : MPOP.AutoLogoff; + + List annos = new List(); + + + if (oldMPOP != owner.MPOPMode) + { + Annotation anno = new Annotation(); + anno.Name = AnnotationNames.MSN_IM_MPOP; + anno.Value = owner.MPOPMode == MPOP.KeepOnline ? "1" : "0"; + annos.Add(anno); + } + + + if (annos.Count > 0 && NSMessageHandler.MSNTicket != MSNTicket.Empty) + { + MsnServiceState ABContactUpdateObject = new MsnServiceState(PartnerScenario.GeneralDialogApply, "ABContactUpdate", true); // In msnp17 this is "GeneralDialogApply" + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, ABContactUpdateObject); + abService.ABContactUpdateCompleted += delegate(object service, ABContactUpdateCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abService, MsnServiceType.AB, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled && e.Error == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "UpdateGeneralDialogSetting completed.", GetType().Name); + AddressBook.MyProperties[AnnotationNames.MSN_IM_MPOP] = owner.MPOPMode == MPOP.KeepOnline ? "1" : "0"; + } + }; + + ABContactUpdateRequestType request = new ABContactUpdateRequestType(); + request.abId = WebServiceConstants.MessengerIndividualAddressBookId; + request.contacts = new ContactType[] { new ContactType() }; + request.contacts[0].contactInfo = new contactInfoType(); + request.contacts[0].contactInfo.contactType = MessengerContactType.Me; + request.contacts[0].contactInfo.annotations = annos.ToArray(); + request.contacts[0].propertiesChanged = PropertyString.Annotation; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abService, MsnServiceType.AB, ABContactUpdateObject, request)); + } + } + + private void UpdatePrivacySettings() + { + Owner owner = NSMessageHandler.ContactList.Owner; + + if (owner == null) + throw new InvalidOperationException("This is not a valid Messenger contact."); + + PrivacyMode oldPrivacy = AddressBook.MyProperties[AnnotationNames.MSN_IM_BLP] == "1" ? PrivacyMode.AllExceptBlocked : PrivacyMode.NoneButAllowed; + NotifyPrivacy oldNotify = AddressBook.MyProperties[AnnotationNames.MSN_IM_GTC] == "1" ? NotifyPrivacy.PromptOnAdd : NotifyPrivacy.AutomaticAdd; + RoamLiveProperty oldRoaming = AddressBook.MyProperties[AnnotationNames.MSN_IM_RoamLiveProperties] == "1" ? RoamLiveProperty.Enabled : RoamLiveProperty.Disabled; + List annos = new List(); + List propertiesChanged = new List(); + + if (oldPrivacy != owner.Privacy) + { + Annotation anno = new Annotation(); + anno.Name = AnnotationNames.MSN_IM_BLP; + anno.Value = owner.Privacy == PrivacyMode.AllExceptBlocked ? "1" : "0"; + annos.Add(anno); + + if (owner.Privacy == PrivacyMode.NoneButAllowed) + owner.SetNotifyPrivacy(NotifyPrivacy.PromptOnAdd); + } + + if (oldNotify != owner.NotifyPrivacy) + { + Annotation anno = new Annotation(); + anno.Name = AnnotationNames.MSN_IM_GTC; + anno.Value = owner.NotifyPrivacy == NotifyPrivacy.PromptOnAdd ? "1" : "0"; + annos.Add(anno); + } + + if (oldRoaming != owner.RoamLiveProperty) + { + Annotation anno = new Annotation(); + anno.Name = AnnotationNames.MSN_IM_RoamLiveProperties; + anno.Value = owner.RoamLiveProperty == RoamLiveProperty.Enabled ? "1" : "2"; + annos.Add(anno); + } + + if (annos.Count > 0) + { + propertiesChanged.Add(PropertyString.Annotation); + } + + // DisplayName + //if (owner.Name != NSMessageHandler.ContactService.Deltas.Profile.DisplayName) + // propertiesChanged.Add("DisplayName"); + + if (propertiesChanged.Count > 0 && NSMessageHandler.MSNTicket != MSNTicket.Empty) + { + MsnServiceState ABContactUpdateObject = new MsnServiceState(PartnerScenario.PrivacyApply, "ABContactUpdate", true); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, ABContactUpdateObject); + abService.ABContactUpdateCompleted += delegate(object service, ABContactUpdateCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abService, MsnServiceType.AB, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled && e.Error == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "UpdateMe completed.", GetType().Name); + + AddressBook.MyProperties[AnnotationNames.MSN_IM_BLP] = owner.Privacy == PrivacyMode.AllExceptBlocked ? "1" : "0"; + AddressBook.MyProperties[AnnotationNames.MSN_IM_GTC] = owner.NotifyPrivacy == NotifyPrivacy.PromptOnAdd ? "1" : "0"; + AddressBook.MyProperties[AnnotationNames.MSN_IM_RoamLiveProperties] = owner.RoamLiveProperty == RoamLiveProperty.Enabled ? "1" : "2"; + } + }; + + ABContactUpdateRequestType request = new ABContactUpdateRequestType(); + request.abId = WebServiceConstants.MessengerIndividualAddressBookId; + request.contacts = new ContactType[] { new ContactType() }; + request.contacts[0].contactInfo = new contactInfoType(); + request.contacts[0].contactInfo.contactType = MessengerContactType.Me; + //request.contacts[0].contactInfo.displayName = owner.Name; + request.contacts[0].contactInfo.annotations = annos.ToArray(); + request.contacts[0].propertiesChanged = String.Join(PropertyString.propertySeparator, propertiesChanged.ToArray()); + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abService, MsnServiceType.AB, ABContactUpdateObject, request)); + } + } + + #endregion + + #region AddContactGroup & RemoveContactGroup & RenameGroup + + /// + /// Send a request to the server to add a new contactgroup. + /// + /// The name of the group to add + public void AddContactGroup(string groupName) + { + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("ABGroupAdd", new MSNPSharpException("You don't have access right on this action anymore."))); + return; + } + + MsnServiceState ABGroupAddObject = new MsnServiceState(PartnerScenario.GroupSave, "ABGroupAdd", true); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, ABGroupAddObject); + abService.ABGroupAddCompleted += delegate(object service, ABGroupAddCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abService, MsnServiceType.AB, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled && e.Error == null) + { + NSMessageHandler.ContactGroups.AddGroup(new ContactGroup(groupName, e.Result.ABGroupAddResult.guid, NSMessageHandler, false)); + NSMessageHandler.ContactService.OnContactGroupAdded(new ContactGroupEventArgs((ContactGroup)NSMessageHandler.ContactGroups[e.Result.ABGroupAddResult.guid])); + } + }; + + ABGroupAddRequestType request = new ABGroupAddRequestType(); + request.abId = WebServiceConstants.MessengerIndividualAddressBookId; + request.groupAddOptions = new ABGroupAddRequestTypeGroupAddOptions(); + request.groupAddOptions.fRenameOnMsgrConflict = false; + request.groupAddOptions.fRenameOnMsgrConflictSpecified = true; + request.groupInfo = new ABGroupAddRequestTypeGroupInfo(); + request.groupInfo.GroupInfo = new groupInfoType(); + request.groupInfo.GroupInfo.name = groupName; + request.groupInfo.GroupInfo.fMessenger = false; + request.groupInfo.GroupInfo.fMessengerSpecified = true; + request.groupInfo.GroupInfo.groupType = WebServiceConstants.MessengerGroupType; + request.groupInfo.GroupInfo.annotations = new Annotation[] { new Annotation() }; + request.groupInfo.GroupInfo.annotations[0].Name = AnnotationNames.MSN_IM_Display; + request.groupInfo.GroupInfo.annotations[0].Value = "1"; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abService, MsnServiceType.AB, ABGroupAddObject, request)); + } + + /// + /// Send a request to the server to remove a contactgroup. Any contacts in the group will also be removed from the forward list. + /// + /// The group to remove + public void RemoveContactGroup(ContactGroup contactGroup) + { + foreach (Contact cnt in NSMessageHandler.ContactList.All) + { + if (cnt.ContactGroups.Contains(contactGroup)) + { + throw new InvalidOperationException("Target group not empty, please remove all contacts form the group first."); + } + } + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("ABGroupDelete", new MSNPSharpException("You don't have access right on this action anymore."))); + return; + } + + MsnServiceState ABGroupDeleteObject = new MsnServiceState(PartnerScenario.Timer, "ABGroupDelete", true); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, ABGroupDeleteObject); + abService.ABGroupDeleteCompleted += delegate(object service, ABGroupDeleteCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abService, MsnServiceType.AB, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled && e.Error == null) + { + NSMessageHandler.ContactGroups.RemoveGroup(contactGroup); + AddressBook.Groups.Remove(new Guid(contactGroup.Guid)); + NSMessageHandler.ContactService.OnContactGroupRemoved(new ContactGroupEventArgs(contactGroup)); + } + }; + + ABGroupDeleteRequestType request = new ABGroupDeleteRequestType(); + request.abId = WebServiceConstants.MessengerIndividualAddressBookId; + request.groupFilter = new groupFilterType(); + request.groupFilter.groupIds = new string[] { contactGroup.Guid }; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abService, MsnServiceType.AB, ABGroupDeleteObject, request)); + } + + + /// + /// Set the name of a contact group + /// + /// The contactgroup which name will be set + /// The new name + public void RenameGroup(ContactGroup group, string newGroupName) + { + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("ABGroupUpdate", new MSNPSharpException("You don't have access right on this action anymore."))); + return; + } + + MsnServiceState ABGroupUpdateObject = new MsnServiceState(PartnerScenario.GroupSave, "ABGroupUpdate", true); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, ABGroupUpdateObject); + abService.ABGroupUpdateCompleted += delegate(object service, ABGroupUpdateCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abService, MsnServiceType.AB, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled && e.Error == null) + { + group.SetName(newGroupName); + } + }; + + ABGroupUpdateRequestType request = new ABGroupUpdateRequestType(); + request.abId = WebServiceConstants.MessengerIndividualAddressBookId; + request.groups = new GroupType[1] { new GroupType() }; + request.groups[0].groupId = group.Guid; + request.groups[0].propertiesChanged = PropertyString.GroupName; //"GroupName"; + request.groups[0].groupInfo = new groupInfoType(); + request.groups[0].groupInfo.name = newGroupName; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abService, MsnServiceType.AB, ABGroupUpdateObject, request)); + } + + #endregion + + #region AddContactToGroup & RemoveContactFromGroup + + public void AddContactToFavoriteGroup(Contact contact) + { + if (contact.Guid == null || contact.Guid == Guid.Empty) + throw new InvalidOperationException("This is not a valid Messenger contact."); + + ContactGroup favGroup = NSMessageHandler.ContactGroups.FavoriteGroup; + + if (favGroup != null && contact.HasGroup(favGroup) == false) + AddContactToGroup(contact, favGroup); + else + throw new InvalidOperationException("No favorite group"); + } + + public void AddContactToGroup(Contact contact, ContactGroup group) + { + if (contact.Guid == null || contact.Guid == Guid.Empty) + throw new InvalidOperationException("This is not a valid Messenger contact."); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("ABGroupContactAdd", new MSNPSharpException("You don't have access right on this action anymore."))); + return; + } + + MsnServiceState ABGroupContactAddObject = new MsnServiceState(PartnerScenario.GroupSave, "ABGroupContactAdd", true); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, ABGroupContactAddObject); + abService.ABGroupContactAddCompleted += delegate(object service, ABGroupContactAddCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abService, MsnServiceType.AB, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled && e.Error == null) + { + contact.AddContactToGroup(group); + } + }; + + ABGroupContactAddRequestType request = new ABGroupContactAddRequestType(); + request.abId = WebServiceConstants.MessengerIndividualAddressBookId; + request.groupFilter = new groupFilterType(); + request.groupFilter.groupIds = new string[] { group.Guid }; + request.contacts = new ContactType[] { new ContactType() }; + request.contacts[0].contactId = contact.Guid.ToString(); + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abService, MsnServiceType.AB, ABGroupContactAddObject, request)); + } + + public void RemoveContactFromFavoriteGroup(Contact contact) + { + if (contact.Guid == null || contact.Guid == Guid.Empty) + throw new InvalidOperationException("This is not a valid Messenger contact."); + + ContactGroup favGroup = NSMessageHandler.ContactGroups.FavoriteGroup; + + if (favGroup != null && contact.HasGroup(favGroup)) + RemoveContactFromGroup(contact, favGroup); + else + throw new InvalidOperationException("No favorite group"); + } + + public void RemoveContactFromGroup(Contact contact, ContactGroup group) + { + if (contact.Guid == null || contact.Guid == Guid.Empty) + throw new InvalidOperationException("This is not a valid Messenger contact."); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("ABGroupContactDelete", new MSNPSharpException("You don't have access right on this action anymore."))); + return; + } + + MsnServiceState ABGroupContactDelete = new MsnServiceState(PartnerScenario.GroupSave, "ABGroupContactDelete", true); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, ABGroupContactDelete); + abService.ABGroupContactDeleteCompleted += delegate(object service, ABGroupContactDeleteCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abService, MsnServiceType.AB, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled && e.Error == null) + { + contact.RemoveContactFromGroup(group); + } + }; + + ABGroupContactDeleteRequestType request = new ABGroupContactDeleteRequestType(); + request.abId = WebServiceConstants.MessengerIndividualAddressBookId; + request.groupFilter = new groupFilterType(); + request.groupFilter.groupIds = new string[] { group.Guid }; + request.contacts = new ContactType[] { new ContactType() }; + request.contacts[0].contactId = contact.Guid.ToString(); + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abService, MsnServiceType.AB, ABGroupContactDelete, request)); + } + #endregion + + #region AddContactToList + + /// + /// Send a request to the server to add this contact to a specific list. + /// + /// The affected contact + /// The list to place the contact in + /// + internal void AddContactToList(Contact contact, MSNLists list, EventHandler onSuccess) + { + if (list == MSNLists.PendingList) //this causes disconnect + return; + + // check whether the update is necessary + if (contact.HasLists(list)) + return; + + Dictionary hashlist = new Dictionary(2); + hashlist.Add(contact.Hash, list); + string payload = ConstructLists(hashlist, false)[0]; + + if (list == MSNLists.ForwardList) + { + NSMessageHandler.MessageProcessor.SendMessage(new NSPayLoadMessage("ADL", payload)); + contact.AddToList(list); + + if (onSuccess != null) + { + onSuccess(this, EventArgs.Empty); + } + + return; + } + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("AddMember", new MSNPSharpException("You don't have access right on this action anymore."))); + return; + } + + MsnServiceState AddMemberObject = new MsnServiceState((list == MSNLists.ReverseList) ? PartnerScenario.ContactMsgrAPI : PartnerScenario.BlockUnblock, "AddMember", true); + SharingServiceBinding sharingService = (SharingServiceBinding)CreateService(MsnServiceType.Sharing, AddMemberObject); + + AddMemberRequestType addMemberRequest = new AddMemberRequestType(); + addMemberRequest.serviceHandle = new HandleType(); + + Service messengerService = AddressBook.SelectTargetService(ServiceFilterType.Messenger); + addMemberRequest.serviceHandle.Id = messengerService.Id.ToString(); + addMemberRequest.serviceHandle.Type = messengerService.ServiceType; + + Membership memberShip = new Membership(); + memberShip.MemberRole = GetMemberRole(list); + BaseMember member = new BaseMember(); + + if (contact.ClientType == ClientType.PassportMember) + { + member = new PassportMember(); + PassportMember passportMember = member as PassportMember; + passportMember.PassportName = contact.Mail; + passportMember.State = MemberState.Accepted; + passportMember.Type = MembershipType.Passport; + } + else if (contact.ClientType == ClientType.EmailMember) + { + member = new EmailMember(); + EmailMember emailMember = member as EmailMember; + emailMember.State = MemberState.Accepted; + emailMember.Type = MembershipType.Email; + emailMember.Email = contact.Mail; + emailMember.Annotations = new Annotation[] { new Annotation() }; + emailMember.Annotations[0].Name = AnnotationNames.MSN_IM_BuddyType; + emailMember.Annotations[0].Value = "32:"; + } + else if (contact.ClientType == ClientType.PhoneMember) + { + member = new PhoneMember(); + PhoneMember phoneMember = member as PhoneMember; + phoneMember.State = MemberState.Accepted; + phoneMember.Type = MembershipType.Phone; + phoneMember.PhoneNumber = contact.Mail; + } + else if (contact.ClientType == ClientType.CircleMember) + { + member = new CircleMember(); + CircleMember circleMember = member as CircleMember; + circleMember.Type = MembershipType.Circle; + circleMember.State = MemberState.Accepted; + circleMember.CircleId = (contact as Circle).AddressBookId.ToString("D").ToLowerInvariant(); + } + + memberShip.Members = new BaseMember[] { member }; + addMemberRequest.memberships = new Membership[] { memberShip }; + + sharingService.AddMemberCompleted += delegate(object service, AddMemberCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(sharingService, MsnServiceType.Sharing, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled) + { + if (null != e.Error && false == e.Error.Message.Contains("Member already exists")) + { + return; + } + + contact.AddToList(list); + AddressBook.AddMemberhip(ServiceFilterType.Messenger, contact.Mail, contact.ClientType, GetMemberRole(list), member, Scenario.ContactServeAPI); + NSMessageHandler.ContactService.OnContactAdded(new ListMutateEventArgs(contact, list)); + + if ((list & MSNLists.AllowedList) == MSNLists.AllowedList || (list & MSNLists.BlockedList) == MSNLists.BlockedList) + { + NSMessageHandler.MessageProcessor.SendMessage(new NSPayLoadMessage("ADL", payload)); + } + + if (onSuccess != null) + { + onSuccess(this, EventArgs.Empty); + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "AddMember completed: " + list, GetType().Name); + } + }; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(sharingService, MsnServiceType.Sharing, AddMemberObject, addMemberRequest)); + } + + #endregion + + #region RemoveContactFromList + + /// + /// Send a request to the server to remove a contact from a specific list. + /// + /// The affected contact + /// The list to remove the contact from + /// + internal void RemoveContactFromList(Contact contact, MSNLists list, EventHandler onSuccess) + { + if (list == MSNLists.ReverseList) //this causes disconnect + return; + + // check whether the update is necessary + if (!contact.HasLists(list)) + return; + + Dictionary hashlist = new Dictionary(2); + hashlist.Add(contact.Hash, list); + string payload = ConstructLists(hashlist, false)[0]; + + if (list == MSNLists.ForwardList) + { + NSMessageHandler.MessageProcessor.SendMessage(new NSPayLoadMessage("RML", payload)); + contact.RemoveFromList(list); + + if (onSuccess != null) + { + onSuccess(this, EventArgs.Empty); + } + return; + } + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("DeleteMember", new MSNPSharpException("You don't have access right on this action anymore."))); + return; + } + + MsnServiceState DeleteMemberObject = new MsnServiceState((list == MSNLists.PendingList) ? PartnerScenario.ContactMsgrAPI : PartnerScenario.BlockUnblock, "DeleteMember", true); + SharingServiceBinding sharingService = (SharingServiceBinding)CreateService(MsnServiceType.Sharing, DeleteMemberObject); + sharingService.DeleteMemberCompleted += delegate(object service, DeleteMemberCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(sharingService, MsnServiceType.Sharing, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled) + { + if (null != e.Error && false == e.Error.Message.Contains("Member does not exist")) + { + return; + } + + contact.RemoveFromList(list); + AddressBook.RemoveMemberhip(ServiceFilterType.Messenger, contact.Mail, contact.ClientType, GetMemberRole(list), Scenario.ContactServeAPI); + NSMessageHandler.ContactService.OnContactRemoved(new ListMutateEventArgs(contact, list)); + + if ((list & MSNLists.AllowedList) == MSNLists.AllowedList || (list & MSNLists.BlockedList) == MSNLists.BlockedList) + { + NSMessageHandler.MessageProcessor.SendMessage(new NSPayLoadMessage("RML", payload)); + } + + if (onSuccess != null) + { + onSuccess(this, EventArgs.Empty); + } + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "DeleteMember completed: " + list, GetType().Name); + } + }; + + DeleteMemberRequestType deleteMemberRequest = new DeleteMemberRequestType(); + deleteMemberRequest.serviceHandle = new HandleType(); + + Service messengerService = AddressBook.SelectTargetService(ServiceFilterType.Messenger); + deleteMemberRequest.serviceHandle.Id = messengerService.Id.ToString(); //Always set to 0 ?? + deleteMemberRequest.serviceHandle.Type = messengerService.ServiceType; + + Membership memberShip = new Membership(); + memberShip.MemberRole = GetMemberRole(list); + + BaseMember deleteMember = null; // BaseMember is an abstract type, so we cannot create a new instance. + // If we have a MembershipId different from 0, just use it. Otherwise, use email or phone number. + BaseMember baseMember = AddressBook.SelectBaseMember(ServiceFilterType.Messenger, contact.Mail, contact.ClientType, GetMemberRole(list)); + int membershipId = (baseMember == null || String.IsNullOrEmpty(baseMember.MembershipId)) ? 0 : int.Parse(baseMember.MembershipId); + + switch (contact.ClientType) + { + case ClientType.PassportMember: + + deleteMember = new PassportMember(); + deleteMember.Type = (baseMember == null) ? MembershipType.Passport : baseMember.Type; + deleteMember.State = (baseMember == null) ? MemberState.Accepted : baseMember.State; + if (membershipId == 0) + { + (deleteMember as PassportMember).PassportName = contact.Mail; + } + break; + + case ClientType.EmailMember: + + deleteMember = new EmailMember(); + deleteMember.Type = (baseMember == null) ? MembershipType.Email : baseMember.Type; + deleteMember.State = (baseMember == null) ? MemberState.Accepted : baseMember.State; + if (membershipId == 0) + { + (deleteMember as EmailMember).Email = contact.Mail; + } + break; + + case ClientType.PhoneMember: + + deleteMember = new PhoneMember(); + deleteMember.Type = (baseMember == null) ? MembershipType.Phone : baseMember.Type; + deleteMember.State = (baseMember == null) ? MemberState.Accepted : baseMember.State; + if (membershipId == 0) + { + (deleteMember as PhoneMember).PhoneNumber = contact.Mail; + } + break; + + case ClientType.CircleMember: + deleteMember = new CircleMember(); + deleteMember.Type = (baseMember == null) ? MembershipType.Circle : baseMember.Type; + deleteMember.State = (baseMember == null) ? MemberState.Accepted : baseMember.State; + (deleteMember as CircleMember).CircleId = (contact as Circle).AddressBookId.ToString("D").ToLowerInvariant(); + break; + } + + deleteMember.MembershipId = membershipId.ToString(); + + memberShip.Members = new BaseMember[] { deleteMember }; + deleteMemberRequest.memberships = new Membership[] { memberShip }; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(sharingService, MsnServiceType.Sharing, DeleteMemberObject, deleteMemberRequest)); + } + + #endregion + + #region BlockContact & UnBlockContact + + /// + /// Block this contact. After this you aren't able to receive messages from this contact. This contact + /// will be placed in your block list and removed from your allowed list. + /// + /// Contact to block + public void BlockContact(Contact contact) + { + if (contact.OnAllowedList) + { + RemoveContactFromList( + contact, + MSNLists.AllowedList, + delegate + { + if (!contact.OnBlockedList) + AddContactToList(contact, MSNLists.BlockedList, null); + } + ); + } + else if (!contact.OnBlockedList) + { + AddContactToList(contact, MSNLists.BlockedList, null); + } + } + + /// + /// Unblock this contact. After this you are able to receive messages from this contact. This contact + /// will be removed from your blocked list and placed in your allowed list. + /// + /// Contact to unblock + public void UnBlockContact(Contact contact) + { + if (contact.OnBlockedList) + { + RemoveContactFromList( + contact, + MSNLists.BlockedList, + delegate + { + if (!contact.OnAllowedList) + AddContactToList(contact, MSNLists.AllowedList, null); + } + ); + } + else if (!contact.OnAllowedList) + { + AddContactToList(contact, MSNLists.AllowedList, null); + } + } + + + #endregion + + #region Create Circle + + /// + /// Use specific name to create a new . event will be fired after creation succeeded. + /// + /// New circle name. + public void CreateCircle(string circleName) + { + MsnServiceState createCircleObject = new MsnServiceState(PartnerScenario.CircleSave, "CreateCircle", true); + string addressBookId = string.Empty; + + SharingServiceBinding sharingService = (SharingServiceBinding)CreateService(MsnServiceType.Sharing, createCircleObject); + CreateCircleRequestType request = new CreateCircleRequestType(); + request.callerInfo = new callerInfoType(); + request.callerInfo.PublicDisplayName = NSMessageHandler.ContactList.Owner.Name == string.Empty ? NSMessageHandler.ContactList.Owner.Mail : NSMessageHandler.ContactList.Owner.Name; + + //This is M$ style, you will never guess out the meaning of these numbers. + ContentInfoType properties = new ContentInfoType(); + properties.Domain = 1; + properties.HostedDomain = CircleString.DefaultHostDomain; + properties.Type = 2; + properties.MembershipAccess = 0; + properties.IsPresenceEnabled = true; + properties.RequestMembershipOption = 2; + properties.DisplayName = circleName; + + request.properties = properties; + sharingService.CreateCircleCompleted += delegate(object sender, CreateCircleCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(sharingService, MsnServiceType.Sharing, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled) + { + if (e.Error != null) + { + return; + } + + abRequest(PartnerScenario.JoinedCircleDuringPush, + delegate + { + lock (AddressBook.PendingCreateCircleList) + { + AddressBook.PendingCreateCircleList[new Guid(e.Result.CreateCircleResult.Id)] = circleName; + } + } + ); + } + }; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(sharingService, MsnServiceType.Sharing, createCircleObject, request)); + } + + #endregion + + + #region Block/UnBlock Circle + + /// + /// Block a specific . The ContactBlocked event of corresponding will be fired after block operation succeeded. + /// + /// The circle to block. + public void BlockCircle(Circle circle) + { + if (circle.OnBlockedList) + return; + + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("AddMember", new MSNPSharpException("You don't have access right on this action anymore."))); + return; + } + + MsnServiceState AddMemberObject = new MsnServiceState(PartnerScenario.BlockUnblock, "AddMember", true); + SharingServiceBinding sharingService = (SharingServiceBinding)CreateService(MsnServiceType.Sharing, AddMemberObject); + + AddMemberRequestType addMemberRequest = new AddMemberRequestType(); + addMemberRequest.serviceHandle = new HandleType(); + + Service messengerService = AddressBook.SelectTargetService(ServiceFilterType.Messenger); + addMemberRequest.serviceHandle.Id = messengerService.Id.ToString(); + addMemberRequest.serviceHandle.Type = messengerService.ServiceType; + + Membership memberShip = new Membership(); + memberShip.MemberRole = MemberRole.Block; + + CircleMember member = new CircleMember(); + + member.Type = MessengerContactType.Circle; + member.State = MemberState.Accepted; + member.CircleId = circle.AddressBookId.ToString(); + + memberShip.Members = new BaseMember[] { member }; + addMemberRequest.memberships = new Membership[] { memberShip }; + + sharingService.AddMemberCompleted += delegate(object service, AddMemberCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(sharingService, MsnServiceType.Sharing, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled) + { + if (null != e.Error && false == e.Error.Message.Contains("Member already exists")) + { + return; + } + + NSMessageHandler.SendBlockCircleNSCommands(circle.AddressBookId, circle.HostDomain); + + circle.RemoveFromList(MSNLists.AllowedList); + circle.AddToList(MSNLists.BlockedList); + circle.SetStatus(PresenceStatus.Offline); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "AddMember completed: " + circle.ToString(), GetType().Name); + } + }; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(sharingService, MsnServiceType.Sharing, AddMemberObject, addMemberRequest)); + } + + /// + /// Unblock a specific . The ContactUnBlocked event of corresponding will be fired after unblock operation succeeded. + /// + /// The affected circle + public void UnBlockCircle(Circle circle) + { + if (!circle.OnBlockedList) + return; + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || AddressBook == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("DeleteMember", new MSNPSharpException("You don't have access right on this action anymore."))); + return; + } + + MsnServiceState DeleteMemberObject = new MsnServiceState(PartnerScenario.BlockUnblock, "DeleteMember", true); + SharingServiceBinding sharingService = (SharingServiceBinding)CreateService(MsnServiceType.Sharing, DeleteMemberObject); + sharingService.DeleteMemberCompleted += delegate(object service, DeleteMemberCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(sharingService, MsnServiceType.Sharing, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled) + { + if (null != e.Error && false == e.Error.Message.Contains("Member does not exist")) + { + return; + } + + NSMessageHandler.SendUnBlockCircleNSCommands(circle.AddressBookId, circle.HostDomain); + circle.RemoveFromList(MSNLists.BlockedList); + circle.AddToList(MSNLists.AllowedList); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "DeleteMember completed: " + circle.ToString(), GetType().Name); + } + }; + + DeleteMemberRequestType deleteMemberRequest = new DeleteMemberRequestType(); + deleteMemberRequest.serviceHandle = new HandleType(); + + Service messengerService = AddressBook.SelectTargetService(ServiceFilterType.Messenger); + deleteMemberRequest.serviceHandle.Id = messengerService.Id.ToString(); //Always set to 0 ?? + deleteMemberRequest.serviceHandle.Type = messengerService.ServiceType; + + Membership memberShip = new Membership(); + memberShip.MemberRole = MemberRole.Block; + + CircleMember clMember = new CircleMember(); + clMember.State = MemberState.Accepted; + clMember.Type = MessengerContactType.Circle; + clMember.CircleId = circle.AddressBookId.ToString(); + + memberShip.Members = new CircleMember[] { clMember }; + deleteMemberRequest.memberships = new Membership[] { memberShip }; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(sharingService, MsnServiceType.Sharing, DeleteMemberObject, deleteMemberRequest)); + } + + + #endregion + + #region Invite/Reject/Accept/Leave circle + + /// + /// Send and invitition to a specific contact to invite it join a . + /// + /// Circle to join. + /// Contact being invited. + public void InviteCircleMember(Circle circle, Contact contact) + { + InviteCircleMember(circle, contact, string.Empty); + } + + /// + /// Send and invitition to a specific contact to invite it join a . A message will send with the invitition. + /// + /// Circle to join. + /// Contact being invited. + /// Message send with the invitition email. + /// One or more parameter(s) is/are null. + /// The owner is not the circle admin or the circle is blocked. + public void InviteCircleMember(Circle circle, Contact contact, string message) + { + if (circle == null || contact == null || message == null) + { + throw new ArgumentNullException(); + } + + if (circle.OnBlockedList) + { + throw new InvalidOperationException("Circle is on your block list."); + } + + if (circle.CircleRole != CirclePersonalMembershipRole.Admin && + circle.CircleRole != CirclePersonalMembershipRole.AssistantAdmin) + { + throw new InvalidOperationException("The owner is not the administrator of this circle."); + } + + if (contact == NSMessageHandler.ContactList.Owner) + return; + + MsnServiceState createContactObject = new MsnServiceState(PartnerScenario.CircleInvite, "CreateContact", true); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, createContactObject); + + CreateContactType request = new CreateContactType(); + + abHandleType handle = new abHandleType(); + handle.ABId = circle.AddressBookId.ToString("D").ToLowerInvariant(); + handle.Puid = 0; + handle.Cid = 0; + + contactHandleType contactHandle = new contactHandleType(); + contactHandle.Email = contact.Mail; + contactHandle.Cid = 0; + contactHandle.Puid = 0; + contactHandle.CircleId = WebServiceConstants.MessengerIndividualAddressBookId; + + request.abHandle = handle; + request.contactHandle = contactHandle; + + abService.CreateContactCompleted += delegate(object sender, CreateContactCompletedEventArgs createContactCompletedArg) + { + OnAfterCompleted(new ServiceOperationEventArgs(abService, MsnServiceType.AB, createContactCompletedArg)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!createContactCompletedArg.Cancelled) + { + if (createContactCompletedArg.Error != null) + return; + + MsnServiceState manageWLConnectionObject = new MsnServiceState(PartnerScenario.CircleInvite, "ManageWLConnection", true); + ABServiceBinding abServiceBinding = (ABServiceBinding)CreateService(MsnServiceType.AB, manageWLConnectionObject); + + ManageWLConnectionRequestType wlconnectionRequest = new ManageWLConnectionRequestType(); + + if (message != string.Empty && message != "") + { + Annotation anno = new Annotation(); + anno.Name = AnnotationNames.MSN_IM_InviteMessage; + anno.Value = message; + Annotation[] annotations = new Annotation[] { anno }; + wlconnectionRequest.annotations = annotations; + } + + wlconnectionRequest.action = 1; + wlconnectionRequest.relationshipType = RelationshipTypes.CircleGroup; + wlconnectionRequest.relationshipRole = (int)CirclePersonalMembershipRole.Member; + + wlconnectionRequest.connection = true; + wlconnectionRequest.presence = false; + + wlconnectionRequest.contactId = createContactCompletedArg.Result.CreateContactResult.contactId; + + wlconnectionRequest.abHandle = handle; + + abServiceBinding.ManageWLConnectionCompleted += delegate(object wlcSender, ManageWLConnectionCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abServiceBinding, MsnServiceType.AB, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (e.Cancelled || e.Error != null) + return; + + if (e.Result.ManageWLConnectionResult.contactInfo.clientErrorData != null && + e.Result.ManageWLConnectionResult.contactInfo.clientErrorData != string.Empty) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "Invite circle member encounted a servier side error: " + + e.Result.ManageWLConnectionResult.contactInfo.clientErrorData); + } + + OnInviteCircleMemberCompleted(new CircleMemberEventArgs(circle, contact)); + return; + + }; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abServiceBinding, MsnServiceType.AB, manageWLConnectionObject, wlconnectionRequest)); + return; + + } + }; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abService, MsnServiceType.AB, createContactObject, request)); + + } + + /// + /// Reject a join circle invitation. + /// + /// Circle to join. + public void RejectCircleInvitation(Circle circle) + { + if (circle == null) + throw new ArgumentNullException("circle"); + + MsnServiceState rejectInviteObject = new MsnServiceState(PartnerScenario.CircleStatus, "ManageWLConnection", true); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, rejectInviteObject); + ManageWLConnectionRequestType wlRequest = new ManageWLConnectionRequestType(); + wlRequest.contactId = circle.Guid.ToString(); + wlRequest.connection = true; + wlRequest.presence = false; + wlRequest.action = 2; + wlRequest.relationshipRole = (int)CirclePersonalMembershipRole.None; + wlRequest.relationshipType = RelationshipTypes.CircleGroup; + + abService.ManageWLConnectionCompleted += delegate(object wlcSender, ManageWLConnectionCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abService, MsnServiceType.AB, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled && e.Error != null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "[RejectCircleInvitation] Reject circle invitation failed: " + circle.ToString()); + } + }; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abService, MsnServiceType.AB, rejectInviteObject, wlRequest)); + } + + internal void FireJoinCircleEvent(JoinCircleInvitationEventArgs arg) + { + if (arg == null) + return; + + Circle circle = arg.Circle; + + if (NSMessageHandler.IsSignedIn) + { + abHandleType abHandle = new abHandleType(); + abHandle.ABId = circle.AddressBookId.ToString().ToLowerInvariant(); + abHandle.Cid = 0; + abHandle.Puid = 0; + + abRequest(PartnerScenario.NewCircleDuringPull, + abHandle, + delegate + { + if (circle.CircleRole == CirclePersonalMembershipRole.StatePendingOutbound) + { + OnJoinCircleInvitationReceived(arg); + } + } + ); + } + else + { + OnJoinCircleInvitationReceived(arg); + } + } + + internal void ServerNotificationRequest(PartnerScenario scene, object[] parameters, ABFindContactsPagedCompletedEventHandler onSuccess) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Executing notify addressbook request, PartnerScenario: " + scene); + + switch (scene) + { + case PartnerScenario.ABChangeNotifyAlert: + msRequest(scene, + delegate + { + ABNotifyChangedSaveReuqest(scene, onSuccess); + } + ); + break; + + case PartnerScenario.CircleIdAlert: + abHandleType abHandler = new abHandleType(); + abHandler.Puid = 0; + abHandler.Cid = 0; + abHandler.ABId = parameters[0].ToString(); + + msRequest(PartnerScenario.MessengerPendingList, + delegate + { + ABNotifyChangedSaveReuqest(scene, onSuccess); + } + ); + break; + } + + } + + private void ABNotifyChangedSaveReuqest(PartnerScenario scene, ABFindContactsPagedCompletedEventHandler onSuccess) + { + abRequest(scene, + delegate(object sender, ABFindContactsPagedCompletedEventArgs e) + { + if (e.Cancelled || e.Error != null) + { + return; + } + + if (e.Result.ABFindContactsPagedResult.Contacts == null + && e.Result.ABFindContactsPagedResult.Groups == null) + { + if (e.Result.ABFindContactsPagedResult.CircleResult == null + || e.Result.ABFindContactsPagedResult.CircleResult.Circles == null) + { + return; + } + } + + lock (SyncObject) + AddressBook.Save(); + + if (onSuccess != null) + onSuccess(sender, e); + } + ); + } + + /// + /// Accept the circle invitation. + /// + /// + /// The circle parameter is null. + /// The circle specified is not a pending circle. + public void AcceptCircleInvitation(Circle circle) + { + if (circle == null) + throw new ArgumentNullException("circle"); + + if (circle.CircleRole != CirclePersonalMembershipRole.StatePendingOutbound) + throw new InvalidOperationException("This is not a pending circle."); + + MsnServiceState acceptInviteObject = new MsnServiceState(PartnerScenario.CircleStatus, "ManageWLConnection", true); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, acceptInviteObject); + ManageWLConnectionRequestType wlRequest = new ManageWLConnectionRequestType(); + wlRequest.contactId = circle.Guid.ToString(); + wlRequest.connection = true; + wlRequest.presence = false; + wlRequest.action = 1; + wlRequest.relationshipRole = (int)CirclePersonalMembershipRole.None; + wlRequest.relationshipType = RelationshipTypes.CircleGroup; + + abService.ManageWLConnectionCompleted += delegate(object wlcSender, ManageWLConnectionCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abService, MsnServiceType.AB, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled) + { + if (e.Error != null) + { + return; + } + + abRequest(PartnerScenario.JoinedCircleDuringPush, null); + } + }; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abService, MsnServiceType.AB, acceptInviteObject, wlRequest)); + } + + /// + /// Leave the specific circle. + /// + /// + /// The circle parameter is null. + public void ExitCircle(Circle circle) + { + if (circle == null) + throw new ArgumentNullException("circle"); + + + string selfGuid = AddressBook.SelectSelfContactGuid(circle.AddressBookId.ToString("D")).ToString("D"); + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Circle contactId: " + selfGuid); + + MsnServiceState leaveCircleObject = new MsnServiceState(PartnerScenario.CircleLeave, "BreakConnection", true); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, leaveCircleObject); + + BreakConnectionRequestType breakconnRequest = new BreakConnectionRequestType(); + + abHandleType handler = new abHandleType(); + handler.ABId = circle.AddressBookId.ToString(); + handler.Cid = 0; + handler.Puid = 0; + + breakconnRequest.abHandle = handler; + breakconnRequest.blockContact = false; + breakconnRequest.deleteContact = true; + breakconnRequest.contactId = selfGuid; + + abService.BreakConnectionCompleted += delegate(object sender, BreakConnectionCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(abService, MsnServiceType.AB, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (e.Cancelled || e.Error != null) + { + if (e.Error != null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "Exit circle: " + circle.AddressBookId.ToString("D") + " failed, error: " + e.Error.Message); + } + return; + } + + NSMessageHandler.SendCircleNotifyRML(circle.AddressBookId, circle.HostDomain, circle.Lists, true); + + lock (SyncObject) + { + AddressBook.RemoveCircle(circle.AddressBookId.ToString("D").ToLowerInvariant()); + AddressBook.Save(); + } + }; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(abService, MsnServiceType.AB, leaveCircleObject, breakconnRequest)); + } + + #endregion + + #endregion + + #region DeleteRecordFile + + /// + /// Delete the record file that contains the contactlist of owner. + /// + public void DeleteRecordFile() + { + if (NSMessageHandler.ContactList.Owner != null && NSMessageHandler.ContactList.Owner.Mail != null) + { + string addressbookFile = Path.Combine(Settings.SavePath, NSMessageHandler.ContactList.Owner.Mail.GetHashCode() + ".mcl"); + if (File.Exists(addressbookFile)) + { + File.SetAttributes(addressbookFile, FileAttributes.Normal); //By default, the file is hidden. + File.Delete(addressbookFile); + } + + string deltasResultFile = Path.Combine(Settings.SavePath, NSMessageHandler.ContactList.Owner.Mail.GetHashCode() + "d" + ".mcl"); + if (File.Exists(deltasResultFile)) + { + if (Deltas != null) + { + Deltas.Truncate(); //If we saved cachekey and preferred host in it, deltas can't be deleted. + } + else + { + File.SetAttributes(deltasResultFile, FileAttributes.Normal); //By default, the file is hidden. + File.Delete(deltasResultFile); + } + } + abSynchronized = false; + } + } + + #endregion + + public string GetMemberRole(MSNLists list) + { + switch (list) + { + case MSNLists.AllowedList: + return MemberRole.Allow; + + case MSNLists.BlockedList: + return MemberRole.Block; + + case MSNLists.PendingList: + return MemberRole.Pending; + + case MSNLists.ReverseList: + return MemberRole.Reverse; + } + return MemberRole.ProfilePersonalContact; + } + + public MSNLists GetMSNList(string memberRole) + { + switch (memberRole) + { + case MemberRole.Allow: + return MSNLists.AllowedList; + case MemberRole.Block: + return MSNLists.BlockedList; + case MemberRole.Reverse: + return MSNLists.ReverseList; + case MemberRole.Pending: + return MSNLists.PendingList; + } + throw new MSNPSharpException("Unknown MemberRole type"); + } + + + + public override void Clear() + { + + lock (SyncObject) + { + base.Clear(); + + recursiveCall = 0; + initialADLs.Clear(); + pendingFQYs.Clear(); + + // Last save for contact list files + if (NSMessageHandler.IsSignedIn && AddressBook != null && Deltas != null) + { + try + { + AddressBook.Save(); + Deltas.Truncate(); + } + catch (Exception error) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, error.Message, GetType().Name); + } + } + + AddressBook = null; + Deltas = null; + abSynchronized = false; + } + } + } +}; diff --git a/MSNPSharp/Services/IPEndPointCallback.cs b/MSNPSharp/Services/IPEndPointCallback.cs new file mode 100644 index 0000000..3d8d09a --- /dev/null +++ b/MSNPSharp/Services/IPEndPointCallback.cs @@ -0,0 +1,73 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Sockets; + +namespace MSNPSharp.Services +{ + internal class IPEndPointCallback + { + private IPEndPoint localEndPoint = null; + + public IPEndPointCallback(IPEndPoint localEndPoint) + { + this.localEndPoint = localEndPoint; + } + + public IPEndPoint BindIPEndPointCallback(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount) + { + if (localEndPoint != null && (localEndPoint.Address == IPAddress.IPv6Any) && remoteEndPoint.AddressFamily == AddressFamily.InterNetwork) + localEndPoint.Address = IPAddress.Any; + + if (localEndPoint != null && (localEndPoint.Address == IPAddress.Any) && remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6) + localEndPoint.Address = IPAddress.IPv6Any; + + if (remoteEndPoint.AddressFamily == AddressFamily.InterNetwork) + { + if (localEndPoint == null) + return new IPEndPoint(IPAddress.Any, 0); + return localEndPoint; + } + else + { + if (localEndPoint == null) + return new IPEndPoint(IPAddress.IPv6Any, 0); + + return localEndPoint; + } + } + } +} diff --git a/MSNPSharp/Services/MSNService.cs b/MSNPSharp/Services/MSNService.cs new file mode 100644 index 0000000..d76f133 --- /dev/null +++ b/MSNPSharp/Services/MSNService.cs @@ -0,0 +1,862 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Net; +using System.Xml; +using System.Text; +using System.Diagnostics; +using System.ComponentModel; +using System.Collections.Generic; +using System.Web.Services.Protocols; + +namespace MSNPSharp +{ + using MSNPSharp.IO; + using MSNPSharp.MSNWS.MSNStorageService; + using MSNPSharp.MSNWS.MSNABSharingService; + using MSNPSharp.MSNWS.MSNRSIService; + using MSNPSharp.MSNWS.MSNOIMStoreService; + using MSNPSharp.Services; + + #region MsnServiceState + + public class MsnServiceState + { + private PartnerScenario partnerScenario; + private string methodName; + private bool addToAsyncList; + + /// + /// Ctor + /// + /// Partner scenario + /// Method name + /// + public MsnServiceState(PartnerScenario scenario, string method, bool async) + { + partnerScenario = scenario; + methodName = method; + addToAsyncList = async; + } + + public PartnerScenario PartnerScenario + { + get + { + return partnerScenario; + } + } + + public string MethodName + { + get + { + return methodName; + } + } + + public bool AddToAsyncList + { + get + { + return addToAsyncList; + } + } + } + #endregion + + #region ServiceOperationEventArgs + public class ServiceOperationEventArgs : EventArgs + { + private SoapHttpClientProtocol webService; + private MsnServiceType serviceType; + private AsyncCompletedEventArgs asyncCompletedEventArgs; + + public MsnServiceState MsnServiceState + { + get + { + return (MsnServiceState)asyncCompletedEventArgs.UserState; + } + } + + public SoapHttpClientProtocol WebService + { + get + { + return webService; + } + } + + public MsnServiceType ServiceType + { + get + { + return serviceType; + } + } + + public AsyncCompletedEventArgs AsyncCompletedEventArgs + { + get + { + return asyncCompletedEventArgs; + } + } + + public ServiceOperationEventArgs(SoapHttpClientProtocol ws, MsnServiceType st, AsyncCompletedEventArgs e) + { + webService = ws; + serviceType = st; + asyncCompletedEventArgs = e; + } + } + + #endregion + + #region BeforeServiceMethodEventArgs + + /// + /// An object contains the calling information for a MSN async webservice method. + /// + public class BeforeRunAsyncMethodEventArgs : EventArgs + { + private SoapHttpClientProtocol webService; + private MsnServiceType serviceType; + private MsnServiceState serviceState; + private object request; + + public SoapHttpClientProtocol WebService + { + get + { + return webService; + } + } + + public MsnServiceType ServiceType + { + get + { + return serviceType; + } + } + + public MsnServiceState ServiceState + { + get + { + return serviceState; + } + } + + public object Request + { + get + { + return request; + } + } + + /// + /// Construct a object. + /// + /// Webservice binding to call. + /// Service type. + /// Service state object. + /// Webservice requst parameter. + public BeforeRunAsyncMethodEventArgs(SoapHttpClientProtocol ws, MsnServiceType st, MsnServiceState ss, object r) + { + webService = ws; + serviceType = st; + serviceState = ss; + request = r; + } + } + + #endregion + + #region ServiceOperationFailedEventArgs + + public class ServiceOperationFailedEventArgs : EventArgs + { + private string method; + private Exception exc; + + public ServiceOperationFailedEventArgs(string methodname, Exception ex) + { + method = methodname; + exc = ex; + } + + public string Method + { + get + { + return method; + } + } + public Exception Exception + { + get + { + return exc; + } + } + } + + #endregion + + /// + /// Base class of webservice-related classes + /// + public abstract class MSNService + { + /// + /// Redirection host for service on *.msnmsgr.escargot.chat + /// + public const string ContactServiceRedirectionHost = @"msnmsgr.escargot.chat"; + + /// + /// Redirection host for service on *.storage.msn.com + /// + public const string StorageServiceRedirectionHost = @"msnmsgr.escargot.chat"; + + + private WebProxy webProxy; + private NSMessageHandler nsMessageHandler; + private Dictionary asyncStates = + new Dictionary(0); + + private Dictionary asyncRequests = + new Dictionary(0); + + private MSNService() + { + } + + protected MSNService(NSMessageHandler nsHandler) + { + nsMessageHandler = nsHandler; + } + + #region Properties + + internal NSMessageHandler NSMessageHandler + { + get + { + return nsMessageHandler; + } + } + + public WebProxy WebProxy + { + get + { + if (NSMessageHandler.ConnectivitySettings != null && NSMessageHandler.ConnectivitySettings.WebProxy != null) + { + webProxy = NSMessageHandler.ConnectivitySettings.WebProxy; + } + + return webProxy; + } + } + + #endregion + + #region Events + + /// + /// Fired when request to an async webservice method failed. + /// + public event EventHandler ServiceOperationFailed; + + /// + /// Fired after asyc web service method completed. + /// + public event EventHandler AfterCompleted; + + /// + /// Fired before asyc web service method. + /// + public event EventHandler BeforeRunAsyncMethod; + + #endregion + + #region CreateService + + protected internal SoapHttpClientProtocol CreateService(MsnServiceType serviceType, MsnServiceState asyncObject) + { + SoapHttpClientProtocol service = null; + IPEndPoint localEndPoint = new IPEndPoint(String.IsNullOrEmpty(NSMessageHandler.ConnectivitySettings.LocalHost) ? IPAddress.Any : IPAddress.Parse(NSMessageHandler.ConnectivitySettings.LocalHost), NSMessageHandler.ConnectivitySettings.LocalPort); + + switch (serviceType) + { + case MsnServiceType.AB: + + SingleSignOnManager.RenewIfExpired(NSMessageHandler, SSOTicketType.Contact); + ABServiceBinding abService = new ABServiceBindingWrapper(localEndPoint); + abService.Proxy = WebProxy; + abService.Timeout = Int32.MaxValue; + abService.UserAgent = Properties.Resources.WebServiceUserAgent; + abService.ABApplicationHeaderValue = new ABApplicationHeader(); + abService.ABApplicationHeaderValue.ApplicationId = NSMessageHandler.Credentials.ClientInfo.ApplicationId; + abService.ABApplicationHeaderValue.IsMigration = false; + abService.ABApplicationHeaderValue.PartnerScenario = Convert.ToString(asyncObject.PartnerScenario); + abService.ABApplicationHeaderValue.CacheKey = NSMessageHandler.MSNTicket.CacheKeys[CacheKeyType.OmegaContactServiceCacheKey]; + abService.ABAuthHeaderValue = new ABAuthHeader(); + abService.ABAuthHeaderValue.TicketToken = NSMessageHandler.MSNTicket.SSOTickets[SSOTicketType.Contact].Ticket; + abService.ABAuthHeaderValue.ManagedGroupRequest = false; + + service = abService; + break; + + case MsnServiceType.Sharing: + + SingleSignOnManager.RenewIfExpired(NSMessageHandler, SSOTicketType.Contact); + + SharingServiceBinding sharingService = new SharingServiceBindingWrapper(localEndPoint); + sharingService.Proxy = WebProxy; + sharingService.Timeout = Int32.MaxValue; + sharingService.UserAgent = Properties.Resources.WebServiceUserAgent; + sharingService.ABApplicationHeaderValue = new ABApplicationHeader(); + sharingService.ABApplicationHeaderValue.ApplicationId = NSMessageHandler.Credentials.ClientInfo.ApplicationId; + sharingService.ABApplicationHeaderValue.IsMigration = false; + sharingService.ABApplicationHeaderValue.PartnerScenario = Convert.ToString(asyncObject.PartnerScenario); + sharingService.ABApplicationHeaderValue.BrandId = NSMessageHandler.MSNTicket.MainBrandID; + sharingService.ABApplicationHeaderValue.CacheKey = NSMessageHandler.MSNTicket.CacheKeys[CacheKeyType.OmegaContactServiceCacheKey]; + sharingService.ABAuthHeaderValue = new ABAuthHeader(); + sharingService.ABAuthHeaderValue.TicketToken = NSMessageHandler.MSNTicket.SSOTickets[SSOTicketType.Contact].Ticket; + sharingService.ABAuthHeaderValue.ManagedGroupRequest = false; + + service = sharingService; + break; + + case MsnServiceType.Storage: + + SingleSignOnManager.RenewIfExpired(NSMessageHandler, SSOTicketType.Storage); + + StorageService storageService = new StorageServiceWrapper(localEndPoint); + storageService.Proxy = WebProxy; + storageService.StorageApplicationHeaderValue = new StorageApplicationHeader(); + storageService.StorageApplicationHeaderValue.ApplicationID = Properties.Resources.ApplicationStrId; + + + storageService.StorageApplicationHeaderValue.Scenario = Convert.ToString(asyncObject.PartnerScenario); + storageService.StorageUserHeaderValue = new StorageUserHeader(); + storageService.StorageUserHeaderValue.Puid = 0; + storageService.StorageUserHeaderValue.TicketToken = NSMessageHandler.MSNTicket.SSOTickets[SSOTicketType.Storage].Ticket; + storageService.AffinityCacheHeaderValue = new AffinityCacheHeader(); + storageService.AffinityCacheHeaderValue.CacheKey = NSMessageHandler.ContactService.Deltas.CacheKeys.ContainsKey(CacheKeyType.StorageServiceCacheKey) + ? NSMessageHandler.ContactService.Deltas.CacheKeys[CacheKeyType.StorageServiceCacheKey] : String.Empty; + + service = storageService; + break; + + case MsnServiceType.RSI: + + SingleSignOnManager.RenewIfExpired(NSMessageHandler, SSOTicketType.Web); + + string[] TandP = NSMessageHandler.MSNTicket.SSOTickets[SSOTicketType.Web].Ticket.Split(new string[] { "t=", "&p=" }, StringSplitOptions.None); + + RSIService rsiService = new RSIServiceWrapper(localEndPoint); + rsiService.Proxy = WebProxy; + rsiService.Timeout = Int32.MaxValue; + rsiService.PassportCookieValue = new PassportCookie(); + rsiService.PassportCookieValue.t = TandP[1]; + rsiService.PassportCookieValue.p = TandP[2]; + + service = rsiService; + break; + + case MsnServiceType.OIMStore: + + SingleSignOnManager.RenewIfExpired(NSMessageHandler, SSOTicketType.OIM); + + OIMStoreService oimService = new OIMStoreServiceWrapper(localEndPoint); + oimService.Proxy = WebProxy; + oimService.TicketValue = new Ticket(); + oimService.TicketValue.passport = NSMessageHandler.MSNTicket.SSOTickets[SSOTicketType.OIM].Ticket; + oimService.TicketValue.lockkey = NSMessageHandler.MSNTicket.OIMLockKey; + oimService.TicketValue.appid = NSMessageHandler.Credentials.ClientID; + + service = oimService; + break; + + case MsnServiceType.WhatsUp: + + SingleSignOnManager.RenewIfExpired(NSMessageHandler, SSOTicketType.WhatsUp); + + WhatsUpServiceBinding wuService = new WhatsUpServiceBindingWrapper(localEndPoint); + wuService.Proxy = WebProxy; + wuService.Timeout = 60000; + wuService.UserAgent = Properties.Resources.WebServiceUserAgent; + wuService.Url = "http://msnmsgr.escargot.chat/whatsnew/whatsnewservice.asmx"; + wuService.WNApplicationHeaderValue = new WNApplicationHeader(); + wuService.WNApplicationHeaderValue.ApplicationId = Properties.Resources.WhatsupServiceAppID; + wuService.WNAuthHeaderValue = new WNAuthHeader(); + wuService.WNAuthHeaderValue.TicketToken = NSMessageHandler.MSNTicket.SSOTickets[SSOTicketType.WhatsUp].Ticket; + + service = wuService; + break; + } + + if (service != null) + { + service.EnableDecompression = Settings.EnableGzipCompressionForWebServices; + + if (asyncObject != null && asyncObject.AddToAsyncList) + { + lock (asyncStates) + asyncStates[service] = asyncObject; + } + } + + return service; + } + + #endregion + + /// + /// Call an async webservice method by using the specific info. + /// + /// + protected virtual void RunAsyncMethod(BeforeRunAsyncMethodEventArgs e) + { + if (e.ServiceState.AddToAsyncList) + { + if (BeforeRunAsyncMethod != null) + { + BeforeRunAsyncMethod(this, e); + } + + ChangeCacheKeyAndPreferredHostForSpecifiedMethod(e.WebService, e.ServiceType, e.ServiceState, e.Request); + + lock (asyncRequests) + { + asyncRequests[e.ServiceState] = e.Request; + } + + + // Run async method now + e.WebService.GetType().InvokeMember( + e.ServiceState.MethodName + "Async", + System.Reflection.BindingFlags.InvokeMethod, + null, + e.WebService, + new object[] { e.Request, e.ServiceState } + ); + } + } + + protected void ChangeCacheKeyAndPreferredHostForSpecifiedMethod(SoapHttpClientProtocol ws, MsnServiceType st, MsnServiceState ss, object request) + { + if (st == MsnServiceType.AB || + st == MsnServiceType.Sharing || + st == MsnServiceType.Storage) + { + DeltasList deltas = NSMessageHandler.ContactService.Deltas; + if (deltas == null) + { + throw new MSNPSharpException("Deltas is null."); + } + + string methodName = ss.MethodName; + string preferredHostKey = ws.ToString() + "." + methodName; + CacheKeyType keyType = (st == MsnServiceType.Storage) ? CacheKeyType.StorageServiceCacheKey : CacheKeyType.OmegaContactServiceCacheKey; + + string originalUrl = ws.Url; + string originalHost = FetchHost(ws.Url); + bool needRequest = false; + + lock (deltas.SyncObject) + { + needRequest = (deltas.CacheKeys.ContainsKey(keyType) == false || + deltas.CacheKeys[keyType] == string.Empty || + (deltas.CacheKeys[keyType] != string.Empty && + (deltas.PreferredHosts.ContainsKey(preferredHostKey) == false || + deltas.PreferredHosts[preferredHostKey] == String.Empty))); + } + + if(needRequest) + { + + try + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, ws.GetType().ToString() + " is requesting a cachekey and preferred host for calling " + methodName); + + switch (keyType) + { + case CacheKeyType.OmegaContactServiceCacheKey: + ws.Url = ws.Url.Replace(originalHost, MSNService.ContactServiceRedirectionHost); + break; + case CacheKeyType.StorageServiceCacheKey: + ws.Url = ws.Url.Replace(originalHost, MSNService.StorageServiceRedirectionHost); + break; + } + + ws.GetType().InvokeMember(methodName, System.Reflection.BindingFlags.InvokeMethod, + null, ws, + new object[] { request }); + } + catch (Exception ex) + { + bool getHost = false; + if (ex.InnerException is WebException && ex.InnerException != null) + { + WebException webException = ex.InnerException as WebException; + HttpWebResponse webResponse = webException.Response as HttpWebResponse; + + if (webResponse != null) + { + if (webResponse.StatusCode == HttpStatusCode.Moved || + webResponse.StatusCode == HttpStatusCode.MovedPermanently || + webResponse.StatusCode == HttpStatusCode.Redirect || + webResponse.StatusCode == HttpStatusCode.RedirectKeepVerb) + { + string redirectUrl = webResponse.Headers[HttpResponseHeader.Location]; + if (!string.IsNullOrEmpty(redirectUrl)) + { + getHost = true; + + lock (deltas.SyncObject) + { + deltas.PreferredHosts[preferredHostKey] = FetchHost(redirectUrl); + deltas.Save(); + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Get redirect URL by HTTP error succeed, method " + methodName + ":\r\n " + + "Original: " + FetchHost(ws.Url) + "\r\n " + + "Redirect: " + FetchHost(redirectUrl) + "\r\n"); + } + + #region Fetch CacheKey + + try + { + XmlDocument errdoc = new XmlDocument(); + string errorMessage = ex.InnerException.Message; + string xmlstr = errorMessage.Substring(errorMessage.IndexOf("", StringComparison.InvariantCultureIgnoreCase) + "".Length); + + //I think the xml parser microsoft used internally is just a super parser, it can ignore everything. + xmlstr = xmlstr.Replace("&", "&"); + xmlstr = xmlstr.Replace("&", "&"); + + errdoc.LoadXml(xmlstr); + + XmlNodeList findnodelist = errdoc.GetElementsByTagName("CacheKey"); + if (findnodelist.Count > 0) + { + deltas.CacheKeys[keyType] = findnodelist[0].InnerText; + } + } + catch (Exception exc) + { + Trace.WriteLineIf( + Settings.TraceSwitch.TraceError, + "An error occured while getting CacheKey:\r\n" + + "Service: " + ws.GetType().ToString() + "\r\n" + + "MethodName: " + methodName + "\r\n" + + "Message: " + exc.Message); + + } + + #endregion + } + } + } + + if (!getHost) + { + Trace.WriteLineIf( + Settings.TraceSwitch.TraceError, + "An error occured while getting CacheKey and Preferred host:\r\n" + + "Service: " + ws.GetType().ToString() + "\r\n" + + "MethodName: " + methodName + "\r\n" + + "Message: " + ex.Message); + lock (deltas.SyncObject) + deltas.PreferredHosts[preferredHostKey] = originalHost; //If there's an error, we must set the host back to its original value. + } + + } + deltas.Save(); + } + + lock (deltas.SyncObject) + { + if (originalHost != null && originalHost != String.Empty) + { + if (deltas.PreferredHosts.ContainsKey(preferredHostKey)) + { + ws.Url = originalUrl.Replace(originalHost, FetchHost(deltas.PreferredHosts[preferredHostKey])); + } + else + { + //This means the redirection URL returns respond content. + lock (deltas.SyncObject) + { + deltas.PreferredHosts[preferredHostKey] = ws.Url; + deltas.Save(); + } + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "The redirect URL returns correct result, use " + ws.Url + " for " + preferredHostKey); + } + } + + // Set cache key + if (st == MsnServiceType.AB) + { + ((ABServiceBinding)ws).ABApplicationHeaderValue.CacheKey = deltas.CacheKeys[keyType]; + } + else if (st == MsnServiceType.Sharing) + { + ((SharingServiceBinding)ws).ABApplicationHeaderValue.CacheKey = deltas.CacheKeys[keyType]; + } + else if (st == MsnServiceType.Storage) + { + ((StorageService)ws).AffinityCacheHeaderValue.CacheKey = deltas.CacheKeys[keyType]; + } + } + } + } + + private string FetchHost(string fullUrl) + { + string httpsHeader = "https://"; + string httpHeader = "http://"; + string sp = "/"; + string host = fullUrl; + + if (fullUrl.StartsWith(httpsHeader)) + { + host = fullUrl.Substring(httpsHeader.Length); + } + + if (fullUrl.StartsWith(httpHeader)) + { + host = fullUrl.Substring(httpHeader.Length); + } + + int spIndex = host.IndexOf(sp); + + if (spIndex > 0) + host = host.Substring(0, spIndex); + + return host; + } + + private void HandleServiceHeader(SoapHttpClientProtocol ws, MsnServiceType st, MsnServiceState ss) + { + ServiceHeader sh = (st == MsnServiceType.AB) ? + ((ABServiceBinding)ws).ServiceHeaderValue : + ((SharingServiceBinding)ws).ServiceHeaderValue; + + if (null != sh && + NSMessageHandler.ContactService != null && + NSMessageHandler.ContactService.Deltas != null) + { + if (sh.CacheKeyChanged) + { + NSMessageHandler.MSNTicket.CacheKeys[CacheKeyType.OmegaContactServiceCacheKey] = sh.CacheKey; + } + + lock (NSMessageHandler.ContactService.Deltas.SyncObject) + { + /* + if (!String.IsNullOrEmpty(sh.PreferredHostName)) + { + string methodKey = ws.ToString() + "." + ss.MethodName; + string preferredHost = FetchHost(sh.PreferredHostName); + if (NSMessageHandler.ContactService.Deltas.PreferredHosts[methodKey] == preferredHost) + return; + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "Update redirect URL by response succeed, method " + ss.MethodName + ":\r\n " + + "Original: " + FetchHost(ws.Url) + "\r\n " + + "Redirect: " + preferredHost + "\r\n"); + + NSMessageHandler.ContactService.Deltas.PreferredHosts[methodKey] = preferredHost; + }*/ + + NSMessageHandler.ContactService.Deltas.Save(); + } + } + } + + protected virtual void OnAfterCompleted(ServiceOperationEventArgs e) + { + object request = null; + lock (asyncRequests) + { + if (asyncRequests.ContainsKey(e.MsnServiceState)) + { + request = asyncRequests[e.MsnServiceState]; + asyncRequests.Remove(e.MsnServiceState); + } + } + + + if (e.MsnServiceState.AddToAsyncList) + { + lock (asyncStates) + asyncStates.Remove(e.WebService); + } + + if (e.AsyncCompletedEventArgs.Cancelled) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, + "Async method cancelled:\r\n" + + "Service: " + e.WebService.ToString() + "\r\n" + + "MethodName: " + e.MsnServiceState.MethodName + "\r\n" + + "PartnerScenario: " + e.MsnServiceState.PartnerScenario); + } + else if (e.AsyncCompletedEventArgs.Error != null) + { + BeforeRunAsyncMethodEventArgs reinvokeArgs = null; + if (e.AsyncCompletedEventArgs.Error is WebException) + { + WebException webException = e.AsyncCompletedEventArgs.Error as WebException; + HttpWebResponse webResponse = webException.Response as HttpWebResponse; + + if (webResponse != null && request != null) + { + if (webResponse.StatusCode == HttpStatusCode.MovedPermanently) + { + DeltasList deltas = NSMessageHandler.ContactService.Deltas; + if (deltas == null) + { + throw new MSNPSharpException("Deltas is null."); + } + + string redirctURL = webResponse.Headers[HttpResponseHeader.Location]; + string preferredHostKey = e.WebService.ToString() + "." + e.MsnServiceState.MethodName; + + lock (deltas.SyncObject) + { + deltas.PreferredHosts[preferredHostKey] = FetchHost(redirctURL); + deltas.Save(); + } + + e.WebService.Url = redirctURL; + + reinvokeArgs = new BeforeRunAsyncMethodEventArgs(e.WebService, e.ServiceType, e.MsnServiceState, request); + } + } + } + + if (reinvokeArgs == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs(e.MsnServiceState.MethodName, e.AsyncCompletedEventArgs.Error)); + } + else + { + RunAsyncMethod(reinvokeArgs); + } + + } + else + { + // HandleServiceHeader + if (NSMessageHandler.MSNTicket != MSNTicket.Empty && + (e.ServiceType == MsnServiceType.AB || e.ServiceType == MsnServiceType.Sharing)) + { + HandleServiceHeader(e.WebService, e.ServiceType, e.MsnServiceState); + } + + // Fire event + if (AfterCompleted != null) + { + AfterCompleted(this, e); + } + } + } + + /// + /// Fires ServiceOperationFailed event. + /// + /// + /// + protected virtual void OnServiceOperationFailed(object sender, ServiceOperationFailedEventArgs e) + { + if (ServiceOperationFailed != null) + ServiceOperationFailed(sender, e); + } + + + private void CancelAndDisposeAysncMethods() + { + if (asyncStates.Count > 0) + { + lock (this) + { + if (asyncStates.Count > 0) + { + Dictionary copyStates = new Dictionary(asyncStates); + asyncStates = new Dictionary(); + asyncRequests = new Dictionary(); + + foreach (KeyValuePair state in copyStates) + { + try + { + state.Key.GetType().InvokeMember("CancelAsync", + System.Reflection.BindingFlags.InvokeMethod, + null, state.Key, + new object[] { state.Value }); + } + catch (Exception error) + { + System.Diagnostics.Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "An error occured while canceling :\r\n" + + "Service: " + state.Key.ToString() + "\r\n" + + "State: " + state.Value.MethodName + "(" + state.Value.GetHashCode() + ")r\n" + + "Message: " + error.Message); + } + finally + { + state.Key.Dispose(); + } + } + copyStates.Clear(); + } + } + } + } + + public virtual void Clear() + { + CancelAndDisposeAysncMethods(); + } + } +}; diff --git a/MSNPSharp/Services/OIMService.cs b/MSNPSharp/Services/OIMService.cs new file mode 100644 index 0000000..47976ba --- /dev/null +++ b/MSNPSharp/Services/OIMService.cs @@ -0,0 +1,695 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Net; +using System.Xml; +using System.Text; +using System.Diagnostics; +using System.Collections.Generic; +using System.Web.Services.Protocols; +using System.Security.Authentication; +using System.Text.RegularExpressions; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + using MSNPSharp.MSNWS.MSNRSIService; + using MSNPSharp.MSNWS.MSNOIMStoreService; + using System.Globalization; + + #region EventArgs + + [Serializable()] + public class OIMSendCompletedEventArgs : EventArgs + { + private Exception error; + private string sender = string.Empty; + private string receiver = string.Empty; + private string message = string.Empty; + private ulong sequence; + + /// + /// OIM sequence number (OIMCount) + /// + public ulong Sequence + { + get + { + return sequence; + } + } + + /// + /// Message content + /// + public string Message + { + get + { + return message; + } + } + + /// + /// InnerException + /// + public Exception Error + { + get + { + return error; + } + } + + /// + /// OIM sender's email. + /// + public string Sender + { + get + { + return sender; + } + } + + /// + /// OIM receiver's email. + /// + public string Receiver + { + get + { + return receiver; + } + } + + public OIMSendCompletedEventArgs() + { + } + + public OIMSendCompletedEventArgs(string senderAccount, string receiverAccount, ulong seq, string content, Exception err) + { + sender = senderAccount; + receiver = receiverAccount; + sequence = seq; + message = content; + error = err; + } + } + + + [Serializable()] + public class OIMReceivedEventArgs : EventArgs + { + private bool isRead = true; + private Guid guid = Guid.Empty; + private DateTime receivedTime = DateTime.Now; + private string email; + private string nickName; + private string message; + + /// + /// The date and time you receive this message. + /// + public DateTime ReceivedTime + { + get + { + return receivedTime; + } + } + + /// + /// Sender account. + /// + public string Email + { + get + { + return email; + } + } + + /// + /// Sender nickname. + /// + public string NickName + { + get + { + return nickName; + } + } + + /// + /// Text message. + /// + public string Message + { + get + { + return message; + } + } + + /// + /// Message ID + /// + public Guid Guid + { + get + { + return guid; + } + } + + /// + /// Set this to true if you don't want to receive this message + /// next time you login. + /// + public bool IsRead + { + get + { + return isRead; + } + set + { + isRead = value; + } + } + + public OIMReceivedEventArgs(DateTime rcvTime, Guid g, string account, string nick, string msg) + { + receivedTime = rcvTime; + guid = g; + email = account; + nickName = nick; + message = msg; + } + } + #endregion + + #region Exceptions + + /// + /// SenderThrottleLimitExceededException + /// If you get this exception, please wait at least 11 seconds then try to send the OIM again. + /// + [Serializable] + public class SenderThrottleLimitExceededException : Exception + { + public SenderThrottleLimitExceededException() + : base("OIM: SenderThrottleLimitExceeded. Please wait 11 seconds to send again...") + { + } + + public SenderThrottleLimitExceededException(string message) + : base(message) + { + } + + public override string ToString() + { + return Message; + } + } + + #endregion + + /// + /// Provides webservice operation for offline messages + /// + public class OIMService : MSNService + { + /// + /// Occurs when receive an OIM. + /// + public event EventHandler OIMReceived; + + /// + /// Fires after an OIM was sent. + /// + public event EventHandler OIMSendCompleted; + + public OIMService(NSMessageHandler nsHandler) + : base(nsHandler) + { + } + + + + internal void ProcessOIM(MimeMessage message, bool initial) + { + if (OIMReceived == null) + return; + + string xmlstr = message.MimeHeader["Mail-Data"]; + if ("too-large" == xmlstr && NSMessageHandler.MSNTicket != MSNTicket.Empty) + { + MsnServiceState getMetadataObject = new MsnServiceState(PartnerScenario.None, "GetMetadata", true); + RSIService rsiService = (RSIService)CreateService(MsnServiceType.RSI, getMetadataObject); + rsiService.GetMetadataCompleted += delegate(object sender, GetMetadataCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(rsiService, MsnServiceType.RSI, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (e.Cancelled) + return; + + if (e.Error == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "GetMetadata completed.", GetType().Name); + + if (e.Result != null && e.Result is Array) + { + foreach (XmlNode m in (XmlNode[])e.Result) + { + if (m.Name == "MD") + { + processOIMS(((XmlNode)m).ParentNode.InnerXml, initial); + break; + } + } + } + } + }; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(rsiService, MsnServiceType.RSI, getMetadataObject, new GetMetadataRequestType())); + return; + } + processOIMS(xmlstr, initial); + } + + /// + /// + /// + /// + /// if true, get all oims and sort by receive date + private void processOIMS(string xmldata, bool initial) + { + if (OIMReceived == null) + return; + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + XmlDocument xdoc = new XmlDocument(); + xdoc.LoadXml(xmldata); + XmlNodeList xnodlst = xdoc.GetElementsByTagName("M"); + List guidstodelete = new List(); + List initialOIMS = new List(); + int oimdeletecount = xnodlst.Count; + + foreach (XmlNode m in xnodlst) + { + DateTime rt = DateTime.Now; + Guid guid = Guid.Empty; + String email = String.Empty; + String friendlyName = String.Empty; + String message = String.Empty; + + foreach (XmlNode a in m) + { + switch (a.Name) + { + case "RT": + rt = XmlConvert.ToDateTime(a.InnerText, XmlDateTimeSerializationMode.RoundtripKind); + break; + + case "E": + email = a.InnerText; + break; + + case "N": + friendlyName = a.InnerText; + break; + + case "I": + guid = new Guid(a.InnerText); + break; + } + } + + MsnServiceState getMessageObject = new MsnServiceState(PartnerScenario.None, "GetMessage", true); + RSIService rsiService = (RSIService)CreateService(MsnServiceType.RSI, getMessageObject); + rsiService.GetMessageCompleted += delegate(object service, GetMessageCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(rsiService, MsnServiceType.RSI, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled && e.Error == null) + { + if (friendlyName != String.Empty && friendlyName.Contains("?")) + { + string[] fn = friendlyName.Split('?'); + Encoding encode = Encoding.UTF8; + try + { + encode = Encoding.GetEncoding(fn[1]); + } + catch (Exception) + { + encode = Encoding.UTF8; + } + + if (fn[2].ToLowerInvariant() == "b") + { + friendlyName = encode.GetString(Convert.FromBase64String(fn[3])); + } + else if (fn[2].ToLowerInvariant() == "q") + { + friendlyName = MSNHttpUtility.QPDecode(fn[3], encode); + } + } + + MimeDictionary headers = new MimeDictionary(Encoding.UTF8.GetBytes(e.Result.GetMessageResult)); + int msgindex = e.Result.GetMessageResult.IndexOf("\n\n"); + if (msgindex != -1) + { + string msgstr = e.Result.GetMessageResult.Substring(msgindex); + + Encoding encoding = Encoding.UTF8; + try + { + encoding = headers[MimeHeaderStrings.Content_Type].HasAttribute("charset") ? Encoding.GetEncoding(headers[MimeHeaderStrings.Content_Type]["charset"]) : Encoding.UTF8; + } + catch (Exception) + { + encoding = Encoding.UTF8; + } + + if (headers["Content-Transfer-Encoding"].Value.ToLowerInvariant().StartsWith("q")) + { + message = MSNHttpUtility.QPDecode(msgstr, encoding); + } + else if (headers["Content-Transfer-Encoding"].Value.ToLowerInvariant().StartsWith("b")) + { + message = encoding.GetString(Convert.FromBase64String(msgstr)); + } + + OIMReceivedEventArgs orea = new OIMReceivedEventArgs(rt, guid, email, friendlyName, message); + + if (initial) + { + initialOIMS.Add(orea); + + // Is this the last OIM? + if (initialOIMS.Count == oimdeletecount) + { + initialOIMS.Sort(CompareDates); + foreach (OIMReceivedEventArgs ea in initialOIMS) + { + OnOIMReceived(this, ea); + if (ea.IsRead) + { + guidstodelete.Add(ea.Guid.ToString()); + } + if (0 == --oimdeletecount && guidstodelete.Count > 0) + { + DeleteOIMMessages(guidstodelete.ToArray()); + } + } + } + } + else + { + OnOIMReceived(this, orea); + if (orea.IsRead) + { + guidstodelete.Add(guid.ToString()); + } + if (0 == --oimdeletecount && guidstodelete.Count > 0) + { + DeleteOIMMessages(guidstodelete.ToArray()); + } + } + } + } + return; + }; + + GetMessageRequestType request = new GetMessageRequestType(); + request.messageId = guid.ToString(); + request.alsoMarkAsRead = false; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(rsiService, MsnServiceType.RSI, getMessageObject, request)); + } + } + + private static int CompareDates(OIMReceivedEventArgs x, OIMReceivedEventArgs y) + { + return x.ReceivedTime.CompareTo(y.ReceivedTime); + } + + private void DeleteOIMMessages(string[] guids) + { + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + MsnServiceState deleteMessagesObject = new MsnServiceState(PartnerScenario.None, "DeleteMessages", true); + RSIService rsiService = (RSIService)CreateService(MsnServiceType.RSI, deleteMessagesObject); + rsiService.DeleteMessagesCompleted += delegate(object service, DeleteMessagesCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(rsiService, MsnServiceType.RSI, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (!e.Cancelled && e.Error == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "DeleteMessages completed.", GetType().Name); + } + }; + + DeleteMessagesRequestType request = new DeleteMessagesRequestType(); + request.messageIds = guids; + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(rsiService, MsnServiceType.RSI, deleteMessagesObject, request)); + } + + private string _RunGuid = Guid.NewGuid().ToString(); + + private void SendOIMMessage(string account, string msg, OIMUserState userstate) + { + Contact contact = NSMessageHandler.ContactList[account]; // Only PassportMembers can receive oims. + if (NSMessageHandler.MSNTicket != MSNTicket.Empty && contact != null && contact.ClientType == ClientType.PassportMember && contact.OnAllowedList) + { + StringBuilder messageTemplate = new StringBuilder( + "MIME-Version: 1.0\r\n" + + "Content-Type: text/plain; charset=UTF-8\r\n" + + "Content-Transfer-Encoding: base64\r\n" + + "X-OIM-Message-Type: OfflineMessage\r\n" + + "X-OIM-Run-Id: {{run_id}}\r\n" + + "X-OIM-Sequence-Num: {seq-num}\r\n" + + "\r\n" + + "{base64_msg}\r\n" + ); + + messageTemplate.Replace("{base64_msg}", Convert.ToBase64String(Encoding.UTF8.GetBytes(msg), Base64FormattingOptions.InsertLineBreaks)); + messageTemplate.Replace("{seq-num}", contact.OIMCount.ToString()); + messageTemplate.Replace("{run_id}", _RunGuid); + + string message = messageTemplate.ToString(); + + if (userstate == null) + userstate = new OIMUserState(contact.OIMCount, account); + + string name48 = NSMessageHandler.ContactList.Owner.Name; + if (name48.Length > 48) + name48 = name48.Substring(47); + + MsnServiceState storeObject = new MsnServiceState(PartnerScenario.None, "Store", true); + OIMStoreService oimService = (OIMStoreService)CreateService(MsnServiceType.OIMStore, storeObject); + oimService.FromValue = new From(); + oimService.FromValue.memberName = NSMessageHandler.ContactList.Owner.Mail; + oimService.FromValue.friendlyName = "=?utf-8?B?" + Convert.ToBase64String(Encoding.UTF8.GetBytes(name48)) + "?="; + oimService.FromValue.buildVer = "8.5.1302"; + oimService.FromValue.msnpVer = "MSNP15"; + oimService.FromValue.lang = System.Globalization.CultureInfo.CurrentCulture.Name; + oimService.FromValue.proxy = "MSNMSGR"; + + oimService.ToValue = new To(); + oimService.ToValue.memberName = account; + + oimService.Sequence = new SequenceType(); + oimService.Sequence.Identifier = new AttributedURI(); + oimService.Sequence.Identifier.Value = "http://messenger.msn.com"; + oimService.Sequence.MessageNumber = userstate.oimcount; + + oimService.StoreCompleted += delegate(object service, StoreCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(oimService, MsnServiceType.OIMStore, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (e.Cancelled == false && e.Error == null) + { + SequenceAcknowledgmentAcknowledgmentRange range = oimService.SequenceAcknowledgmentValue.AcknowledgmentRange[0]; + if (range.Lower == userstate.oimcount && range.Upper == userstate.oimcount) + { + contact.OIMCount++; // Sent successfully. + OnOIMSendCompleted(this, + new OIMSendCompletedEventArgs( + NSMessageHandler.ContactList.Owner.Mail, + userstate.account, + userstate.oimcount, + msg, + null)); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, "An OIM Message has been sent: " + userstate.account + ", runId = " + _RunGuid, GetType().Name); + } + } + else if (e.Error != null && e.Error is SoapException) + { + SoapException soapexp = e.Error as SoapException; + Exception exp = soapexp; + if (soapexp.Code.Name == "AuthenticationFailed") + { + NSMessageHandler.MSNTicket.OIMLockKey = QRYFactory.CreateQRY(NSMessageHandler.Credentials.ClientID, NSMessageHandler.Credentials.ClientCode, soapexp.Detail.InnerText); + oimService.TicketValue.lockkey = NSMessageHandler.MSNTicket.OIMLockKey; + if (userstate.RecursiveCall++ < 5) + { + SendOIMMessage(account, msg, userstate); // Call this method again. + return; + } + exp = new AuthenticationException("OIM:AuthenticationFailed"); + } + else if (soapexp.Code.Name == "SenderThrottleLimitExceeded") + { + exp = new SenderThrottleLimitExceededException(); + + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, exp.Message, GetType().Name); + } + + OnOIMSendCompleted(this, + new OIMSendCompletedEventArgs( + NSMessageHandler.ContactList.Owner.Mail, + userstate.account, + userstate.oimcount, + msg, + exp) + ); + } + }; + oimService.StoreAsync(MessageType.text, message, storeObject); + } + } + + /// + /// Send an offline message to a contact. + /// + /// Target user + /// Plain text message + public void SendOIMMessage(string account, string msg) + { + SendOIMMessage(account, msg, null); + } + + /// + /// Send an offline message to a contact(only for MSNP18). + /// + /// Target user + /// to send + public void SendOIMMessage(Contact receiver, TextMessage msg) + { + Exception err = null; + try + { + TextMessage txtmsgClone = msg.Clone() as TextMessage; + MimeMessage mimeMessage = new MimeMessage(); + + mimeMessage.MimeHeader[MimeHeaderStrings.Content_Type] = "text/plain; charset=UTF-8"; + mimeMessage.MimeHeader[MimeHeaderStrings.X_MMS_IM_Format] = msg.GetStyleString(); + + mimeMessage.InnerMessage = txtmsgClone; + mimeMessage.MimeHeader["Dest-Agent"] = "client"; + + NSMessage nsMessage = new NSMessage("UUM", + new string[] { receiver.Mail, + ((int)receiver.ClientType).ToString(), + ((int)NetworkMessageType.Text).ToString(CultureInfo.InvariantCulture) }); + + nsMessage.InnerMessage = mimeMessage; + + NSMessageHandler.MessageProcessor.SendMessage(nsMessage); + } + catch (Exception exp) + { + err = exp; + } + + OnOIMSendCompleted(this, + new OIMSendCompletedEventArgs( + NSMessageHandler.ContactList.Owner.Mail, + receiver.Mail, + 0, + msg.Text, + err)); + + + } + + protected virtual void OnOIMReceived(object sender, OIMReceivedEventArgs e) + { + if (OIMReceived != null) + { + OIMReceived(sender, e); + } + } + + protected virtual void OnOIMSendCompleted(object sender, OIMSendCompletedEventArgs e) + { + if (OIMSendCompleted != null) + { + OIMSendCompleted(sender, e); + } + } + } + + internal class OIMUserState + { + public int RecursiveCall; + public readonly ulong oimcount; + public readonly string account = String.Empty; + public OIMUserState(ulong oimCount, string account) + { + this.oimcount = oimCount; + this.account = account; + } + } +}; diff --git a/MSNPSharp/Services/OIMStoreServiceWrapper.cs b/MSNPSharp/Services/OIMStoreServiceWrapper.cs new file mode 100644 index 0000000..a8ed52a --- /dev/null +++ b/MSNPSharp/Services/OIMStoreServiceWrapper.cs @@ -0,0 +1,75 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Sockets; + +namespace MSNPSharp.Services +{ + using MSNPSharp.MSNWS.MSNOIMStoreService; + + [System.Web.Services.WebServiceBindingAttribute(Name = "OIMBinding", Namespace = "http://messenger.msn.com/ws/2004/09/oim/")] + internal sealed class OIMStoreServiceWrapper : OIMStoreService + { + private IPEndPoint localEndPoint = null; + + public OIMStoreServiceWrapper() + : base() + { + } + + public OIMStoreServiceWrapper(IPEndPoint localEndPoint) + : base() + { + this.localEndPoint = localEndPoint; + } + + + protected override WebRequest GetWebRequest(Uri uri) + { + WebRequest request = base.GetWebRequest(uri); + if (request is HttpWebRequest) + { + (request as HttpWebRequest).ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint((new IPEndPointCallback(localEndPoint)).BindIPEndPointCallback); + } + + return request; + } + + + + } +} + diff --git a/MSNPSharp/Services/RSIServiceWrapper.cs b/MSNPSharp/Services/RSIServiceWrapper.cs new file mode 100644 index 0000000..9295701 --- /dev/null +++ b/MSNPSharp/Services/RSIServiceWrapper.cs @@ -0,0 +1,72 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Sockets; + +namespace MSNPSharp.Services +{ + using MSNPSharp.MSNWS.MSNRSIService; + + [System.Web.Services.WebServiceBindingAttribute(Name = "RSIBinding", Namespace = "http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] + internal sealed class RSIServiceWrapper : RSIService + { + private IPEndPoint localEndPoint = null; + + public RSIServiceWrapper() + : base() + { + } + + public RSIServiceWrapper(IPEndPoint localEndPoint) + : base() + { + this.localEndPoint = localEndPoint; + } + + + protected override WebRequest GetWebRequest(Uri uri) + { + WebRequest request = base.GetWebRequest(uri); + if (request is HttpWebRequest) + { + (request as HttpWebRequest).ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint((new IPEndPointCallback(localEndPoint)).BindIPEndPointCallback); + } + + return request; + } + } +} + diff --git a/MSNPSharp/Services/SecurityTokenServiceWrapper.cs b/MSNPSharp/Services/SecurityTokenServiceWrapper.cs new file mode 100644 index 0000000..064a408 --- /dev/null +++ b/MSNPSharp/Services/SecurityTokenServiceWrapper.cs @@ -0,0 +1,177 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Sockets; +using System.Xml; +using System.IO; +using System.Globalization; +using System.Net.Cache; +using System.Web.Services; +using System.Diagnostics; +using System.Security.Permissions; +using System.Web.Services.Protocols; + +namespace MSNPSharp.Services +{ + using MSNPSharp.MSNWS.MSNSecurityTokenService; + using MSNPSharp.Framework; + + + [System.Web.Services.WebServiceBindingAttribute(Name = "SecurityTokenServicePortBinding", Namespace = "http://schemas.microsoft.com/Passport/SoapServices/PPCRL")] + public sealed class SecurityTokenServiceWrapper : SecurityTokenService + { + private IPEndPoint localEndPoint = null; + + public SecurityTokenServiceWrapper() + : base() + { + } + + public SecurityTokenServiceWrapper(IPEndPoint localEndPoint) + : base() + { + this.localEndPoint = localEndPoint; + } + + protected override WebRequest GetWebRequest(Uri uri) + { + WebRequest request = base.GetWebRequest(uri); + if (request is HttpWebRequest) + { + (request as HttpWebRequest).ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint((new IPEndPointCallback(localEndPoint)).BindIPEndPointCallback); + } + + return request; + } + + protected override WebResponse GetWebResponse(WebRequest request) + { + request.ContentType = ContentType.ApplicationSoap; + WebResponse response = base.GetWebResponse(request); + if (!ContentType.IsSoap(response.ContentType)) + response.Headers[HttpResponseHeader.ContentType] = response.ContentType.Replace(ContentType.TextHtml, ContentType.ApplicationSoap); + return response; + } + + protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result) + { + request.ContentType = ContentType.ApplicationSoap; + + WebResponse response = base.GetWebResponse(request, result); + if (!ContentType.IsSoap(response.ContentType)) + response.Headers[HttpResponseHeader.ContentType] = response.ContentType.Replace(ContentType.TextHtml, ContentType.ApplicationSoap); + return response; + } + + [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")] + protected override XmlReader GetReaderForMessage(SoapClientMessage message, int bufferSize) + { + string xmlMatchSchema = ""; + int schemaLength = Encoding.UTF8.GetByteCount(xmlMatchSchema); + Stream messageStream = message.Stream; + byte[] schemaArray = new byte[schemaLength]; + + if (messageStream.CanSeek) + { + long originalPosition = messageStream.Position; + + messageStream.Seek(0, SeekOrigin.Begin); + int bytesRead = messageStream.Read(schemaArray, 0, schemaArray.Length); + + string readSchema = Encoding.UTF8.GetString(schemaArray); + if (readSchema.ToLowerInvariant() != xmlMatchSchema.ToLowerInvariant()) + { + messageStream.Seek(0, SeekOrigin.Begin); + byte[] content = new byte[messageStream.Length]; + messageStream.Read(content, 0, content.Length); + messageStream.Seek(0, SeekOrigin.Begin); + + string strContent = Encoding.UTF8.GetString(content); + + MemoryStream newMemStream = new MemoryStream(); + newMemStream.Seek(0, SeekOrigin.Begin); + newMemStream.Write(Encoding.UTF8.GetBytes(xmlSchema), 0, Encoding.UTF8.GetByteCount(xmlSchema)); + newMemStream.Write(content, 0, content.Length); + newMemStream.Seek(0, SeekOrigin.Begin); + + XmlTextReader reader = null; + Encoding encoding = (message.SoapVersion == SoapProtocolVersion.Soap12) ? RequestResponseUtils.GetEncoding2(message.ContentType) : RequestResponseUtils.GetEncoding(message.ContentType); + if (bufferSize < 0x200) + { + bufferSize = 0x200; + } + + if (encoding != null) + { + reader = new XmlTextReader(new StreamReader(message.Stream, encoding, true, bufferSize)); + } + else + { + reader = new XmlTextReader(message.Stream); + } + reader.ProhibitDtd = true; + reader.Normalization = true; + reader.XmlResolver = null; + return reader; + } + else + { + messageStream.Seek(originalPosition, SeekOrigin.Begin); + return base.GetReaderForMessage(message, bufferSize); + } + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "Unseekable stream returned with message, maybe the connection has terminated. Stream type: " + message.Stream.GetType().ToString()); + return base.GetReaderForMessage(message, bufferSize); + } + } + + [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")] + protected override XmlWriter GetWriterForMessage(SoapClientMessage message, int bufferSize) + { + if (bufferSize < 0x200) + { + bufferSize = 0x200; + } + + return new XmlSpecialNSPrefixTextWriter(new StreamWriter(message.Stream, (base.RequestEncoding != null) ? base.RequestEncoding : new UTF8Encoding(false), bufferSize)); + } + } + + +} diff --git a/MSNPSharp/Services/SharingServiceBindingWrapper.cs b/MSNPSharp/Services/SharingServiceBindingWrapper.cs new file mode 100644 index 0000000..3e6744a --- /dev/null +++ b/MSNPSharp/Services/SharingServiceBindingWrapper.cs @@ -0,0 +1,71 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Sockets; + +namespace MSNPSharp.Services +{ + using MSNPSharp.MSNWS.MSNABSharingService; + + [System.Web.Services.WebServiceBindingAttribute(Name = "SharingServiceBinding", Namespace = "http://www.msn.com/webservices/AddressBook")] + internal sealed class SharingServiceBindingWrapper: SharingServiceBinding + { + private IPEndPoint localEndPoint = null; + + public SharingServiceBindingWrapper() + : base() + { + } + + public SharingServiceBindingWrapper(IPEndPoint localEndPoint) + : base() + { + this.localEndPoint = localEndPoint; + } + + + protected override WebRequest GetWebRequest(Uri uri) + { + WebRequest request = base.GetWebRequest(uri); + if (request is HttpWebRequest) + { + (request as HttpWebRequest).ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint((new IPEndPointCallback(localEndPoint)).BindIPEndPointCallback); + } + + return request; + } + } +} diff --git a/MSNPSharp/Services/StorageService.cs b/MSNPSharp/Services/StorageService.cs new file mode 100644 index 0000000..2ec8c99 --- /dev/null +++ b/MSNPSharp/Services/StorageService.cs @@ -0,0 +1,1079 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Net; +using System.Xml; +using System.Text; +using System.Drawing; +using System.Threading; +using System.Diagnostics; +using System.Globalization; +using System.Net.Sockets; +using System.Collections.Generic; + +namespace MSNPSharp +{ + using MSNPSharp.IO; + using MSNPSharp.MSNWS.MSNABSharingService; + using MSNPSharp.MSNWS.MSNStorageService; + using MSNPSharp.Core; + using MSNPSharp.Services; + + /// + /// Provide webservice operations for Storage Service + /// + public class MSNStorageService : MSNService + { + public MSNStorageService(NSMessageHandler nsHandler) + : base(nsHandler) + { + } + + #region Internal implementation + + private static ExpressionProfileAttributesType CreateFullExpressionProfileAttributes() + { + ExpressionProfileAttributesType expAttrib = new ExpressionProfileAttributesType(); + expAttrib.DateModified = true; + expAttrib.DateModifiedSpecified = true; + expAttrib.DisplayName = true; + expAttrib.DisplayNameLastModified = true; + expAttrib.DisplayNameLastModifiedSpecified = true; + expAttrib.DisplayNameSpecified = true; + expAttrib.Flag = true; + expAttrib.FlagSpecified = true; + expAttrib.PersonalStatus = true; + expAttrib.PersonalStatusLastModified = true; + expAttrib.PersonalStatusLastModifiedSpecified = true; + expAttrib.PersonalStatusSpecified = true; + expAttrib.Photo = true; + expAttrib.PhotoSpecified = true; + expAttrib.Attachments = true; + expAttrib.AttachmentsSpecified = true; + expAttrib.ResourceID = true; + expAttrib.ResourceIDSpecified = true; + expAttrib.StaticUserTilePublicURL = true; + expAttrib.StaticUserTilePublicURLSpecified = true; + + return expAttrib; + } + + private bool CreateProfileSync(PartnerScenario scenario, out string profileResourceId) + { + + //1. CreateProfile, create a new profile and return its resource id. + MsnServiceState serviceState = new MsnServiceState(scenario, "CreateProfile", false); + StorageService storageService = (StorageService)CreateService(MsnServiceType.Storage, serviceState); + + CreateProfileRequestType createRequest = new CreateProfileRequestType(); + createRequest.profile = new CreateProfileRequestTypeProfile(); + createRequest.profile.ExpressionProfile = new ExpressionProfile(); + createRequest.profile.ExpressionProfile.PersonalStatus = ""; + createRequest.profile.ExpressionProfile.RoleDefinitionName = "ExpressionProfileDefault"; + + try + { + ChangeCacheKeyAndPreferredHostForSpecifiedMethod(storageService, MsnServiceType.Storage, serviceState, createRequest); + CreateProfileResponse createResponse = storageService.CreateProfile(createRequest); + profileResourceId = createResponse.CreateProfileResult; + NSMessageHandler.ContactService.Deltas.Profile.ResourceID = profileResourceId; + NSMessageHandler.ContactService.Deltas.Save(true); + } + catch (Exception ex) + { + OnServiceOperationFailed(storageService, new ServiceOperationFailedEventArgs("CreateProfile", ex)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "CreateProfile error: " + ex.Message, GetType().Name); + profileResourceId = string.Empty; + + return false; + } + + return true; + } + + private bool ShareItemSync(PartnerScenario scenario, string profileResourceId) + { + MsnServiceState serviceState = new MsnServiceState(scenario, "ShareItem", false); + StorageService storageService = (StorageService)CreateService(MsnServiceType.Storage, serviceState); + + ShareItemRequestType shareItemRequest = new ShareItemRequestType(); + shareItemRequest.resourceID = profileResourceId; + shareItemRequest.displayName = "Messenger Roaming Identity"; + try + { + ChangeCacheKeyAndPreferredHostForSpecifiedMethod(storageService, MsnServiceType.Storage, serviceState, shareItemRequest); + storageService.ShareItem(shareItemRequest); + } + catch (Exception ex) + { + OnServiceOperationFailed(storageService, new ServiceOperationFailedEventArgs("ShareItem", ex)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "ShareItem error: " + ex.Message, GetType().Name); //Item already shared. + return false; + } + + return true; + } + + private bool AddProfileExpressionRoleMemberSync(PartnerScenario scenario) + { + HandleType srvHandle = new HandleType(); + srvHandle.ForeignId = "MyProfile"; + srvHandle.Id = "0"; + srvHandle.Type = ServiceFilterType.Profile; + if (NSMessageHandler.MSNTicket != MSNTicket.Empty) + { + MsnServiceState serviceState = new MsnServiceState(scenario, "AddMember", false); + SharingServiceBinding sharingService = (SharingServiceBinding)CreateService(MsnServiceType.Sharing, serviceState); + + AddMemberRequestType addMemberRequest = new AddMemberRequestType(); + + addMemberRequest.serviceHandle = srvHandle; + + Membership memberShip = new Membership(); + memberShip.MemberRole = MemberRole.ProfileExpression; + RoleMember roleMember = new RoleMember(); + roleMember.Type = "Role"; + roleMember.Id = "Allow"; + roleMember.State = MemberState.Accepted; + roleMember.MaxRoleRecursionDepth = "0"; + roleMember.MaxDegreesSeparation = "0"; + + RoleMemberDefiningService defService = new RoleMemberDefiningService(); + defService.ForeignId = ""; + defService.Id = "0"; + defService.Type = "Messenger"; + + roleMember.DefiningService = defService; + memberShip.Members = new RoleMember[] { roleMember }; + addMemberRequest.memberships = new Membership[] { memberShip }; + try + { + ChangeCacheKeyAndPreferredHostForSpecifiedMethod(sharingService, MsnServiceType.Sharing, serviceState, addMemberRequest); + sharingService.AddMember(addMemberRequest); + } + catch (Exception ex) + { + OnServiceOperationFailed(sharingService, new ServiceOperationFailedEventArgs("ShareItem", ex)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "AddMember error: " + ex.Message, GetType().Name); + return false; + } + + return true; + } + + return false; + } + + private InternalOperationReturnValues GetProfileLiteSync(PartnerScenario scenario, out string profileResourceId, out string expressionProfileResourceId) + { + MsnServiceState serviceState = new MsnServiceState(scenario, "GetProfile", false); + StorageService storageService = (StorageService)CreateService(MsnServiceType.Storage, serviceState); + + GetProfileRequestType getprofileRequest = new GetProfileRequestType(); + + Alias alias = new Alias(); + alias.NameSpace = "MyCidStuff"; + alias.Name = Convert.ToString(NSMessageHandler.ContactList.Owner.CID); + + Handle pHandle = new Handle(); + pHandle.RelationshipName = "MyProfile"; + pHandle.Alias = alias; + + getprofileRequest.profileHandle = pHandle; + getprofileRequest.profileAttributes = new profileAttributes(); + + ExpressionProfileAttributesType expAttrib = CreateFullExpressionProfileAttributes(); + + getprofileRequest.profileAttributes.ExpressionProfileAttributes = expAttrib; + + try + { + ChangeCacheKeyAndPreferredHostForSpecifiedMethod(storageService, MsnServiceType.Storage, serviceState, getprofileRequest); + GetProfileResponse response = storageService.GetProfile(getprofileRequest); + + #region Process Profile + profileResourceId = response.GetProfileResult.ResourceID; + + if (response.GetProfileResult.ExpressionProfile == null) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Get profile cannot get expression profile of this owner."); + NSMessageHandler.ContactService.Deltas.Profile.HasExpressionProfile = false; + NSMessageHandler.ContactService.Deltas.Profile.DisplayName = NSMessageHandler.ContactList.Owner.Name; + + expressionProfileResourceId = string.Empty; + return InternalOperationReturnValues.NoExpressionProfile; + } + else + { + NSMessageHandler.ContactService.Deltas.Profile.HasExpressionProfile = true; + NSMessageHandler.ContactService.Deltas.Profile.ExpressionProfile.ResourceID = response.GetProfileResult.ExpressionProfile.ResourceID; + NSMessageHandler.ContactService.Deltas.Profile.ExpressionProfile.DateModified = response.GetProfileResult.ExpressionProfile.DateModified; + + expressionProfileResourceId = response.GetProfileResult.ExpressionProfile.ResourceID; + } + + NSMessageHandler.ContactService.Deltas.Profile.DateModified = response.GetProfileResult.DateModified; + NSMessageHandler.ContactService.Deltas.Profile.ResourceID = response.GetProfileResult.ResourceID; + + // Display name + NSMessageHandler.ContactService.Deltas.Profile.DisplayName = response.GetProfileResult.ExpressionProfile.DisplayName; + + // Personal status + if (response.GetProfileResult.ExpressionProfile.PersonalStatus != null) + { + NSMessageHandler.ContactService.Deltas.Profile.PersonalMessage = response.GetProfileResult.ExpressionProfile.PersonalStatus; + } + + NSMessageHandler.ContactService.Deltas.Save(true); + + // Display photo + if (null != response.GetProfileResult.ExpressionProfile.Photo) + { + foreach (DocumentStream docStream in response.GetProfileResult.ExpressionProfile.Photo.DocumentStreams) + { + if (docStream.DocumentStreamType != "UserTileStatic") + { + continue; + } + + if (NSMessageHandler.ContactService.Deltas.Profile.Photo.PreAthURL == docStream.PreAuthURL) + { + + DisplayImage newDisplayImage = new DisplayImage(NSMessageHandler.ContactList.Owner.Mail.ToLowerInvariant(), NSMessageHandler.ContactService.Deltas.Profile.Photo.DisplayImage); + + NSMessageHandler.ContactList.Owner.DisplayImage = newDisplayImage; + } + else + { + string requesturi = docStream.PreAuthURL; + if (requesturi.StartsWith("/")) + { + requesturi = "http://blufiles.storage.msn.com" + requesturi; //I found it http://byfiles.storage.msn.com is also ok + } + + // Don't urlencode t= :)) + string usertitleURL = requesturi + "?t=" + System.Web.HttpUtility.UrlEncode(NSMessageHandler.MSNTicket.SSOTickets[SSOTicketType.Storage].Ticket.Substring(2)); + SyncUserTile(usertitleURL, + delegate(object nullParam) + { + NSMessageHandler.ContactService.Deltas.Profile.Photo.Name = response.GetProfileResult.ExpressionProfile.Photo.Name; + NSMessageHandler.ContactService.Deltas.Profile.Photo.DateModified = response.GetProfileResult.ExpressionProfile.Photo.DateModified; + NSMessageHandler.ContactService.Deltas.Profile.Photo.ResourceID = response.GetProfileResult.ExpressionProfile.Photo.ResourceID; + NSMessageHandler.ContactService.Deltas.Profile.Photo.PreAthURL = docStream.PreAuthURL; + SerializableMemoryStream ms = new SerializableMemoryStream(); + NSMessageHandler.ContactList.Owner.DisplayImage.Image.Save(ms, NSMessageHandler.ContactList.Owner.DisplayImage.Image.RawFormat); + NSMessageHandler.ContactService.Deltas.Profile.Photo.DisplayImage = ms; + NSMessageHandler.ContactService.Deltas.Save(true); + }, + null, + delegate(object param) + { + Exception ex = param as Exception; + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "Get DisplayImage error: " + ex.Message, GetType().Name); + if (NSMessageHandler.ContactList.Owner.UserTileURL != null) + { + SyncUserTile(NSMessageHandler.ContactList.Owner.UserTileURL.AbsoluteUri, null, null, null); + } + }); + + } + } + } + + #endregion + } + catch (Exception ex) + { + OnServiceOperationFailed(storageService, new ServiceOperationFailedEventArgs("GetProfile", ex)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "GetProfile error: " + ex.Message, GetType().FullName); + expressionProfileResourceId = string.Empty; + profileResourceId = string.Empty; + + if (ex.Message.ToLowerInvariant().Contains("does not exist")) + { + return InternalOperationReturnValues.ProfileNotExist; + } + + + return InternalOperationReturnValues.RequestFailed; + } + + return InternalOperationReturnValues.Succeed; + } + + private bool CreatePhotoDocumentSync(PartnerScenario scenario, out string documentResourceId, string photoName, byte[] photoData) + { + if (photoData == null) + { + documentResourceId = string.Empty; + return false; + } + + MsnServiceState serviceState = new MsnServiceState(scenario, "CreateDocument", false); + StorageService storageService = (StorageService)CreateService(MsnServiceType.Storage, serviceState); + + + CreateDocumentRequestType createDocRequest = new CreateDocumentRequestType(); + createDocRequest.relationshipName = "Messenger User Tile"; + + Handle parenthandle = new Handle(); + parenthandle.RelationshipName = "/UserTiles"; + + Alias alias = new Alias(); + alias.NameSpace = "MyCidStuff"; + alias.Name = Convert.ToString(NSMessageHandler.ContactList.Owner.CID); + + parenthandle.Alias = alias; + createDocRequest.parentHandle = parenthandle; + createDocRequest.document = new Photo(); + createDocRequest.document.Name = photoName; + + PhotoStream photoStream = new PhotoStream(); + photoStream.DataSize = 0; + photoStream.MimeType = "png"; + photoStream.DocumentStreamType = "UserTileStatic"; + photoStream.Data = photoData; + createDocRequest.document.DocumentStreams = new PhotoStream[] { photoStream }; + + DisplayImage displayImage = new DisplayImage(NSMessageHandler.ContactList.Owner.Mail.ToLowerInvariant(), new MemoryStream(photoData)); + + NSMessageHandler.ContactList.Owner.DisplayImage = displayImage; + + try + { + ChangeCacheKeyAndPreferredHostForSpecifiedMethod(storageService, MsnServiceType.Storage, serviceState, createDocRequest); + CreateDocumentResponseType createDocResponse = storageService.CreateDocument(createDocRequest); + documentResourceId = createDocResponse.CreateDocumentResult; + } + catch (Exception ex) + { + OnServiceOperationFailed(storageService, new ServiceOperationFailedEventArgs("CreateDocument", ex)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "CreateDocument error: " + ex.Message, GetType().Name); + documentResourceId = string.Empty; + return false; + } + + NSMessageHandler.ContactService.Deltas.Profile.Photo.Name = photoName; + NSMessageHandler.ContactService.Deltas.Profile.Photo.DisplayImage = new SerializableMemoryStream(); + NSMessageHandler.ContactService.Deltas.Profile.Photo.DisplayImage.Write(photoData, 0, photoData.Length); + NSMessageHandler.ContactService.Deltas.Save(true); + + return true; + } + + private bool CreateRelationshipsSync(PartnerScenario scenario, string expressionProfileResourceId, string documentResourceId) + { + if (string.IsNullOrEmpty(expressionProfileResourceId) || string.IsNullOrEmpty(documentResourceId)) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "CreateRelationships error: expression profile Id or document resource Id is empty."); + return false; + } + + MsnServiceState serviceState = new MsnServiceState(scenario, "CreateRelationships", false); + StorageService storageService = (StorageService)CreateService(MsnServiceType.Storage, serviceState); + + CreateRelationshipsRequestType createRelationshipRequest = new CreateRelationshipsRequestType(); + Relationship relationship = new Relationship(); + relationship.RelationshipName = "ProfilePhoto"; + relationship.SourceType = "SubProfile"; //From SubProfile + relationship.TargetType = "Photo"; //To Photo + relationship.SourceID = expressionProfileResourceId; //From Expression profile + relationship.TargetID = documentResourceId; //To Document + + createRelationshipRequest.relationships = new Relationship[] { relationship }; + try + { + ChangeCacheKeyAndPreferredHostForSpecifiedMethod(storageService, MsnServiceType.Storage, serviceState, createRelationshipRequest); + storageService.CreateRelationships(createRelationshipRequest); + } + catch (Exception ex) + { + OnServiceOperationFailed(storageService, new ServiceOperationFailedEventArgs("CreateRelationships", ex)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "CreateRelationships error: " + ex.Message, GetType().Name); + return false; + } + + return true; + } + + private bool DeleteRelationshipByNameSync(PartnerScenario scenario, string relationshipName, string targetHandlerResourceId) + { + MsnServiceState serviceState = new MsnServiceState(scenario, "DeleteRelationships", false); + StorageService storageService = (StorageService)CreateService(MsnServiceType.Storage, serviceState); + + Alias mycidAlias = new Alias(); + mycidAlias.Name = Convert.ToString(NSMessageHandler.ContactList.Owner.CID); + mycidAlias.NameSpace = "MyCidStuff"; + + // 3. DeleteRelationships. If an error occurs, don't return, continue... + + // 3.1 UserTiles -> Photo + DeleteRelationshipsRequestType request = new DeleteRelationshipsRequestType(); + request.sourceHandle = new Handle(); + request.sourceHandle.RelationshipName = relationshipName; //"/UserTiles"; + request.sourceHandle.Alias = mycidAlias; + request.targetHandles = new Handle[] { new Handle() }; + request.targetHandles[0].ResourceID = targetHandlerResourceId; + try + { + ChangeCacheKeyAndPreferredHostForSpecifiedMethod(storageService, MsnServiceType.Storage, serviceState, request); + storageService.DeleteRelationships(request); + } + catch (Exception ex) + { + OnServiceOperationFailed(storageService, new ServiceOperationFailedEventArgs("DeleteRelationships", ex)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, ex.Message, GetType().Name); + return false; + } + + return true; + + + } + + private bool DeleteRelationshipByResourceIdSync(PartnerScenario scenario, string sourceHandlerResourceId, string targetHandlerResourceId) + { + if (string.IsNullOrEmpty(sourceHandlerResourceId) || string.IsNullOrEmpty(targetHandlerResourceId)) + return false; + + MsnServiceState serviceState = new MsnServiceState(scenario, "DeleteRelationships", false); + StorageService storageService = (StorageService)CreateService(MsnServiceType.Storage, serviceState); + + //3.2 Profile -> Photo + DeleteRelationshipsRequestType request = new DeleteRelationshipsRequestType(); + request.sourceHandle = new Handle(); + request.sourceHandle.ResourceID = sourceHandlerResourceId; + request.targetHandles = new Handle[] { new Handle() }; + request.targetHandles[0].ResourceID = targetHandlerResourceId; + try + { + ChangeCacheKeyAndPreferredHostForSpecifiedMethod(storageService, MsnServiceType.Storage, serviceState, request); + storageService.DeleteRelationships(request); + } + catch (Exception ex) + { + OnServiceOperationFailed(storageService, new ServiceOperationFailedEventArgs("DeleteRelationships", ex)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, ex.Message, GetType().Name); + return false; + } + + return true; + } + + private bool UpdatePhotoDocumentSync(PartnerScenario scenario, string photoName, string documentResourceId, byte[] photoData) + { + if (string.IsNullOrEmpty(documentResourceId) || photoData == null) + return false; + + MsnServiceState serviceState = new MsnServiceState(scenario, "UpdateDocument", false); + StorageService storageService = (StorageService)CreateService(MsnServiceType.Storage, serviceState); + + UpdateDocumentRequestType request = new UpdateDocumentRequestType(); + request.document = new Photo(); + + if (!string.IsNullOrEmpty(photoName)) + { + request.document.Name = photoName; + } + + + request.document.ResourceID = documentResourceId; + request.document.DocumentStreams = new PhotoStream[] { new PhotoStream() }; + request.document.DocumentStreams[0].DataSize = 0; + request.document.DocumentStreams[0].MimeType = "image/png"; + request.document.DocumentStreams[0].DocumentStreamType = "UserTileStatic"; + request.document.DocumentStreams[0].Data = photoData; + + try + { + ChangeCacheKeyAndPreferredHostForSpecifiedMethod(storageService, MsnServiceType.Storage, serviceState, request); + storageService.UpdateDocument(request); + } + catch (Exception ex) + { + OnServiceOperationFailed(storageService, new ServiceOperationFailedEventArgs("UpdateDocument", ex)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, ex.Message, GetType().Name); + return false; + } + + NSMessageHandler.ContactService.Deltas.Profile.Photo.Name = photoName; + NSMessageHandler.ContactService.Deltas.Profile.Photo.DisplayImage = new SerializableMemoryStream(); + NSMessageHandler.ContactService.Deltas.Profile.Photo.DisplayImage.Write(photoData, 0, photoData.Length); + NSMessageHandler.ContactService.Deltas.Save(true); + + return true; + } + + private bool UpdateProfileLiteSync(PartnerScenario scenario, string profileResourceId, string displayName, string personalStatus, string freeText, int flag) + { + MsnServiceState serviceState = new MsnServiceState(scenario, "UpdateProfile", false); + StorageService storageService = (StorageService)CreateService(MsnServiceType.Storage, serviceState); + + UpdateProfileRequestType updateProfileRequest = new UpdateProfileRequestType(); + updateProfileRequest.profile = new UpdateProfileRequestTypeProfile(); + updateProfileRequest.profile.ResourceID = profileResourceId; + ExpressionProfile expProf = new ExpressionProfile(); + expProf.FreeText = freeText; + expProf.DisplayName = displayName; + expProf.Flags = flag; + expProf.FlagsSpecified = true; + + if (!string.IsNullOrEmpty(personalStatus)) + { + expProf.PersonalStatus = personalStatus; + } + updateProfileRequest.profile.ExpressionProfile = expProf; + + NSMessageHandler.ContactService.Deltas.Profile.DisplayName = displayName; + NSMessageHandler.ContactService.Deltas.Profile.PersonalMessage = personalStatus; + NSMessageHandler.ContactService.Deltas.Save(true); //Save no matter the request succeed or fail. + + try + { + ChangeCacheKeyAndPreferredHostForSpecifiedMethod(storageService, MsnServiceType.Storage, serviceState, updateProfileRequest); + storageService.UpdateProfile(updateProfileRequest); + } + catch (Exception ex) + { + OnServiceOperationFailed(storageService, new ServiceOperationFailedEventArgs("UpdateProfile", ex)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "UpdateProfile error: " + ex.Message, GetType().Name); + return false; + } + + return true; + } + + private bool AddDynamicItemSync(PartnerScenario scenario) + { + if (NSMessageHandler.MSNTicket != MSNTicket.Empty) + { + MsnServiceState serviceState = new MsnServiceState(scenario, "AddDynamicItem", false); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, serviceState); + + PassportDynamicItem newDynamicItem = new PassportDynamicItem(); + newDynamicItem.Type = "Passport"; + newDynamicItem.PassportName = NSMessageHandler.ContactList.Owner.Mail; + + AddDynamicItemRequestType addDynamicItemRequest = new AddDynamicItemRequestType(); + addDynamicItemRequest.abId = WebServiceConstants.MessengerIndividualAddressBookId; + addDynamicItemRequest.dynamicItems = new BaseDynamicItemType[] { newDynamicItem }; + + try + { + + ChangeCacheKeyAndPreferredHostForSpecifiedMethod(abService, MsnServiceType.AB, serviceState, addDynamicItemRequest); + abService.AddDynamicItem(addDynamicItemRequest); + } + catch (Exception ex) + { + OnServiceOperationFailed(abService, new ServiceOperationFailedEventArgs("AddDynamicItem", ex)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "AddDynamicItem error: " + ex.Message, GetType().Name); + return false; + } + return true; + } + + return false; + } + + private bool UpdateDynamicItemSync(PartnerScenario scenario) + { + if (NSMessageHandler.MSNTicket != MSNTicket.Empty) + { + //9. UpdateDynamicItem + MsnServiceState serviceState = new MsnServiceState(scenario, "UpdateDynamicItem", false); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, serviceState); + + UpdateDynamicItemRequestType updateDyItemRequest = new UpdateDynamicItemRequestType(); + updateDyItemRequest.abId = Guid.Empty.ToString(); + + PassportDynamicItem passportDyItem = new PassportDynamicItem(); + passportDyItem.Type = "Passport"; + passportDyItem.PassportName = NSMessageHandler.ContactList.Owner.Mail; + passportDyItem.Changes = "Notifications"; + + NotificationDataType notification = new NotificationDataType(); + notification.Status = "Exist Access"; + notification.InstanceId = "0"; + notification.Gleam = false; + notification.LastChanged = NSMessageHandler.ContactService.Deltas.Profile.DateModified; + + ServiceType srvInfo = new ServiceType(); + srvInfo.Changes = ""; + + HandleType srvHandle = new HandleType(); + srvHandle.ForeignId = "MyProfile"; + srvHandle.Id = "0"; + srvHandle.Type = ServiceFilterType.Profile; + + InfoType info = new InfoType(); + info.Handle = srvHandle; + info.IsBot = false; + info.InverseRequired = false; + + srvInfo.Info = info; + notification.StoreService = srvInfo; + passportDyItem.Notifications = new NotificationDataType[] { notification }; + updateDyItemRequest.dynamicItems = new PassportDynamicItem[] { passportDyItem }; + try + { + + ChangeCacheKeyAndPreferredHostForSpecifiedMethod(abService, MsnServiceType.AB, serviceState, updateDyItemRequest); + abService.UpdateDynamicItem(updateDyItemRequest); + } + catch (Exception ex) + { + OnServiceOperationFailed(abService, new ServiceOperationFailedEventArgs("UpdateDynamicItem", ex)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "UpdateDynamicItem error: You don't receive any contact updates, vice versa! " + ex.Message, GetType().Name); + + AddDynamicItemRequestType addDynamicItemRequest = new AddDynamicItemRequestType(); + addDynamicItemRequest.abId = updateDyItemRequest.abId; + addDynamicItemRequest.dynamicItems = updateDyItemRequest.dynamicItems; + foreach (BaseDynamicItemType dynamicItem in addDynamicItemRequest.dynamicItems) + { + dynamicItem.Notifications = null; + dynamicItem.Changes = null; + dynamicItem.LastChanged = null; + } + + try + { + ChangeCacheKeyAndPreferredHostForSpecifiedMethod(abService, MsnServiceType.AB, serviceState, addDynamicItemRequest); + abService.AddDynamicItem(addDynamicItemRequest); + } + catch (Exception exAddDynamicItem) + { + OnServiceOperationFailed(abService, new ServiceOperationFailedEventArgs("AddDynamicItem", exAddDynamicItem)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "AddDynamicItem error: You don't receive any contact updates, vice versa! " + exAddDynamicItem.Message, GetType().Name); + return false; + } + return true; + } + return true; + } + + return false; + } + + private bool UpdateContactSync(PartnerScenario scenario) + { + if (NSMessageHandler.MSNTicket != MSNTicket.Empty) + { + MsnServiceState serviceState = new MsnServiceState(scenario, "ABContactUpdate", false); + ABServiceBinding abService = (ABServiceBinding)CreateService(MsnServiceType.AB, serviceState); + + ABContactUpdateRequestType abcontactUpdateRequest = new ABContactUpdateRequestType(); + abcontactUpdateRequest.abId = Guid.Empty.ToString(); + + ContactType meContact = new ContactType(); + meContact.propertiesChanged = PropertyString.Annotation; //"Annotation"; + + contactInfoType meinfo = new contactInfoType(); + meinfo.contactType = MessengerContactType.Me; + + Annotation anno = new Annotation(); + anno.Name = AnnotationNames.MSN_IM_RoamLiveProperties; + anno.Value = "1"; + + meinfo.annotations = new Annotation[] { anno }; + meContact.contactInfo = meinfo; + abcontactUpdateRequest.contacts = new ContactType[] { meContact }; + try + { + + ChangeCacheKeyAndPreferredHostForSpecifiedMethod(abService, MsnServiceType.AB, serviceState, abcontactUpdateRequest); + abService.ABContactUpdate(abcontactUpdateRequest); + } + catch (Exception ex) + { + OnServiceOperationFailed(abService, new ServiceOperationFailedEventArgs("ABContactUpdate", ex)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, "ABContactUpdate error: " + ex.Message, GetType().Name); + return false; + } + return true; + } + return false; + } + + /// + /// Initialize the user profile if the contact connect to live network the firt time. + /// + /// CreateProfile + /// ShareItem + /// AddMember + /// [GetProfile] + /// CreateDocument + /// CreateRelationships + /// UpdateProfile + /// FindDocuments + /// AddDynamicItem + /// UpdateDynamicItem + /// ABContactUpdate + /// + /// 10 steps, what the hell!! If M$ change any protocol in their strageservice, it will be a disaster to find the difference. + /// + private void CreateProfile() + { + if (NSMessageHandler.MSNTicket == MSNTicket.Empty || NSMessageHandler.ContactService.Deltas == null) + return; + if (NSMessageHandler.ContactService.Deltas.Profile.HasExpressionProfile == false) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "No expression profile exists, create profile skipped."); + NSMessageHandler.ContactList.Owner.CreateDefaultDisplayImage(null); //Set default + + return; + } + + try + { + string profileResourceId = string.Empty; + string expressionProfileResourceId = string.Empty; + string documentReourceId = string.Empty; + bool nextStep = false; + InternalOperationReturnValues getprofileResult = InternalOperationReturnValues.Succeed; + + + //1. CreateProfile, create a new profile and return its resource id. + nextStep = CreateProfileSync(PartnerScenario.RoamingSeed, out profileResourceId); + + //2. ShareItem, share the profile. + if (nextStep) + { + + nextStep = ShareItemSync(PartnerScenario.RoamingSeed, profileResourceId); + + //3. AddMember, add a ProfileExpression role member into the newly created profile and define messenger service. + AddProfileExpressionRoleMemberSync(PartnerScenario.RoamingSeed); + } + + // [GetProfile], get the new ProfileExpression resource id. + getprofileResult = GetProfileLiteSync(PartnerScenario.RoamingSeed,out profileResourceId, out expressionProfileResourceId); + + //4. CreateDocument, create a new document for this profile and return its resource id. + MemoryStream defaultDisplayImageStream = new MemoryStream(); + Properties.Resources.MSNPSharp_logo.Save(defaultDisplayImageStream, Properties.Resources.MSNPSharp_logo.RawFormat); + nextStep = CreatePhotoDocumentSync(PartnerScenario.RoamingSeed, out documentReourceId, "MSNPSharp", defaultDisplayImageStream.ToArray()); + + //5. CreateRelationships, create a relationship between ProfileExpression role member and the new document. + if (expressionProfileResourceId != string.Empty && documentReourceId != string.Empty) + { + nextStep = CreateRelationshipsSync(PartnerScenario.RoamingSeed, expressionProfileResourceId, documentReourceId); + } + + //6.1 UpdateProfile + if (profileResourceId != string.Empty) + { + nextStep = UpdateProfileLiteSync(PartnerScenario.RoamingSeed, profileResourceId, NSMessageHandler.ContactList.Owner.NickName, string.Empty, "Update", 0); + } + + // 6.2 Get Profile again to get notification.LastChanged + if (expressionProfileResourceId != string.Empty) + { + getprofileResult = GetProfileLiteSync(PartnerScenario.RoamingSeed, out profileResourceId, out expressionProfileResourceId); + } + + //7. FindDocuments Hmm.... + + //8. AddDynamicItem + nextStep = AddDynamicItemSync(PartnerScenario.RoamingSeed); + if (nextStep) + { + //9. UpdateDynamicItem + nextStep = UpdateDynamicItemSync(PartnerScenario.RoamingSeed); + } + + //10. ABContactUpdate + nextStep = UpdateContactSync(PartnerScenario.RoamingSeed); + + //11. OK, there's no 11, that's all.... + } + catch (Exception ex) + { + Trace.WriteLine(ex.Message); + } + } + + private OwnerProfile GetProfileImpl(PartnerScenario scenario) + { + string expressProfileId = string.Empty; + string profileResourceId = string.Empty; + + try + { + InternalOperationReturnValues result = GetProfileLiteSync(scenario, out profileResourceId, out expressProfileId); + + if (result == InternalOperationReturnValues.ProfileNotExist) + { + CreateProfile(); + } + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, + "GetProfileLiteSync Error." + ex.Message + "\r\n" + ex.StackTrace); + } + + if (NSMessageHandler.ContactService.Deltas == null) + { + return null; + } + + return NSMessageHandler.ContactService.Deltas.Profile; + } + + internal delegate void GetUsertitleByURLhandler(object param); + + internal void SyncUserTile(string usertitleURL, GetUsertitleByURLhandler callBackHandler, object param, GetUsertitleByURLhandler errorHandler) + { + try + { + Uri uri = new Uri(usertitleURL); + + HttpWebRequest fwr = (HttpWebRequest)WebRequest.Create(uri); + fwr.Proxy = WebProxy; + fwr.Timeout = 30000; + fwr.ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint(new IPEndPointCallback(new IPEndPoint(String.IsNullOrEmpty(NSMessageHandler.ConnectivitySettings.LocalHost) ? IPAddress.Any : IPAddress.Parse(NSMessageHandler.ConnectivitySettings.LocalHost), NSMessageHandler.ConnectivitySettings.LocalPort)).BindIPEndPointCallback); + + fwr.BeginGetResponse(delegate(IAsyncResult result) + { + try + { + Stream stream = ((WebRequest)result.AsyncState).EndGetResponse(result).GetResponseStream(); + SerializableMemoryStream ms = new SerializableMemoryStream(); + byte[] data = new byte[8192]; + int read; + while ((read = stream.Read(data, 0, data.Length)) > 0) + { + ms.Write(data, 0, read); + } + stream.Close(); + + DisplayImage newDisplayImage = new DisplayImage(NSMessageHandler.ContactList.Owner.Mail.ToLowerInvariant(), ms); + + NSMessageHandler.ContactList.Owner.DisplayImage = newDisplayImage; + if (callBackHandler != null) + { + callBackHandler(param); + } + } + catch (Exception ex) + { + if (errorHandler != null) + errorHandler(ex); + + return; + } + + }, fwr); + } + catch (Exception e) + { + if (errorHandler != null) + errorHandler(e); + + return; + } + } + + + private void UpdateProfileImpl(string displayName, string personalStatus, string freeText, int flags) + { + + + if (NSMessageHandler.ContactList.Owner.RoamLiveProperty == RoamLiveProperty.Enabled && + NSMessageHandler.ContactService.Deltas.Profile.HasExpressionProfile && + NSMessageHandler.BotMode == false) + { + UpdateProfileLiteSync(PartnerScenario.RoamingIdentityChanged, + NSMessageHandler.ContactService.Deltas.Profile.ResourceID, + displayName, + personalStatus, + freeText, + flags); + + // And get profile again + NSMessageHandler.ContactService.Deltas.Profile = GetProfileImpl(PartnerScenario.RoamingIdentityChanged); + + // UpdateDynamicItem + UpdateDynamicItemSync(PartnerScenario.RoamingIdentityChanged); + + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Roaming disabled or invalid expression profile. Update skipped."); + NSMessageHandler.ContactService.Deltas.Profile.DisplayName = displayName; + NSMessageHandler.ContactService.Deltas.Profile.PersonalMessage = personalStatus; + NSMessageHandler.ContactService.Deltas.Save(true); + } + + } + + #endregion + + /// + /// Get my profile. Display name, personal status and display photo. + /// + public OwnerProfile GetProfile() + { + if (NSMessageHandler.BotMode == false) + { + if (NSMessageHandler.ContactService.Deltas == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("GetProfile", new MSNPSharpException("You don't have access right on this action anymore."))); + return null; + } + + if (NSMessageHandler.ContactList.Owner.RoamLiveProperty == RoamLiveProperty.Enabled && NSMessageHandler.MSNTicket != MSNTicket.Empty) + { + DateTime deltasProfileDateModified = WebServiceDateTimeConverter.ConvertToDateTime(NSMessageHandler.ContactService.Deltas.Profile.DateModified); + DateTime annotationLiveProfileExpressionLastChanged = WebServiceDateTimeConverter.ConvertToDateTime(NSMessageHandler.ContactService.AddressBook.MyProperties[AnnotationNames.Live_Profile_Expression_LastChanged]); + + if ((annotationLiveProfileExpressionLastChanged == DateTime.MinValue) || + (deltasProfileDateModified < annotationLiveProfileExpressionLastChanged)) + { + return GetProfileImpl(PartnerScenario.Initial); + } + } + } + else + { + if (NSMessageHandler.ContactService.Deltas.Profile.Photo.DisplayImage == null) + { + SerializableMemoryStream serStream = new SerializableMemoryStream(); + Properties.Resources.MSNPSharp_logo.Save(serStream, Properties.Resources.MSNPSharp_logo.RawFormat); + + NSMessageHandler.ContactService.Deltas.Profile.Photo.DisplayImage = serStream; + NSMessageHandler.ContactService.Deltas.Profile.HasExpressionProfile = false; + NSMessageHandler.ContactService.Deltas.Save(true); + } + } + + return NSMessageHandler.ContactService.Deltas.Profile; + } + + /// + /// Update personal displayname and status in profile + /// + /// + /// + public void UpdateProfile(string displayName, string personalStatus) + { + if (NSMessageHandler.ContactService.Deltas == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("UpdateProfile", new MSNPSharpException("You don't have access right on this action anymore."))); + return; + } + + if (NSMessageHandler.MSNTicket != MSNTicket.Empty && + (NSMessageHandler.ContactService.Deltas.Profile.DisplayName != displayName || + NSMessageHandler.ContactService.Deltas.Profile.PersonalMessage != personalStatus)) + { + UpdateProfileImpl(displayName, personalStatus, "Update", 0); + } + } + + + /// + /// Update the display photo of current user. + /// + /// GetProfile with scenario = "RoamingIdentityChanged" + /// UpdateDynamicItem + /// + /// + /// New photo to display + /// The resourcename + public bool UpdateProfile(Image photo, string photoName) + { + if (NSMessageHandler.ContactService.Deltas == null) + { + OnServiceOperationFailed(this, new ServiceOperationFailedEventArgs("UpdateProfile", new MSNPSharpException("You don't have access right on this action anymore."))); + return false; + } + + if (NSMessageHandler.ContactService.Deltas.Profile.HasExpressionProfile == false) //Non-expression id or provisioned account. + { + NSMessageHandler.ContactService.Deltas.Profile.Photo.Name = photoName; + NSMessageHandler.ContactService.Deltas.Profile.Photo.DisplayImage = new SerializableMemoryStream(); + photo.Save(NSMessageHandler.ContactService.Deltas.Profile.Photo.DisplayImage, photo.RawFormat); + NSMessageHandler.ContactService.Deltas.Save(true); + + DisplayImage newDisplayImage = new DisplayImage(NSMessageHandler.ContactList.Owner.Mail.ToLowerInvariant(), NSMessageHandler.ContactService.Deltas.Profile.Photo.DisplayImage); + + NSMessageHandler.ContactList.Owner.DisplayImage = newDisplayImage; + + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "No expression profile exists, new profile is saved locally."); + return true; + } + + if (NSMessageHandler.ContactList.Owner.RoamLiveProperty == RoamLiveProperty.Enabled && + NSMessageHandler.MSNTicket != MSNTicket.Empty) + { + SerializableMemoryStream mem = SerializableMemoryStream.FromImage(photo); + + // 1. Getprofile + NSMessageHandler.ContactService.Deltas.Profile = GetProfileImpl(PartnerScenario.RoamingIdentityChanged); + + bool updateDocumentResult = false; + // 1.1 UpdateDocument + if (!String.IsNullOrEmpty(NSMessageHandler.ContactService.Deltas.Profile.Photo.ResourceID)) + { + updateDocumentResult = UpdatePhotoDocumentSync(PartnerScenario.RoamingIdentityChanged, + NSMessageHandler.ContactService.Deltas.Profile.Photo.Name, + NSMessageHandler.ContactService.Deltas.Profile.Photo.ResourceID, + mem.ToArray()); + + // UpdateDynamicItem + if (updateDocumentResult) + { + updateDocumentResult = UpdateDynamicItemSync(PartnerScenario.RoamingIdentityChanged); + } + } + + if (updateDocumentResult == false && + NSMessageHandler.ContactService.Deltas.Profile.HasExpressionProfile) + { + string resourceId = string.Empty; + CreatePhotoDocumentSync(PartnerScenario.RoamingIdentityChanged, out resourceId, photoName, mem.ToArray()); + UpdateDynamicItemSync(PartnerScenario.RoamingIdentityChanged); + } + + NSMessageHandler.ContactService.Deltas.Profile = GetProfileImpl(PartnerScenario.RoamingIdentityChanged); + + return true; + } + + return false; + } + } +}; diff --git a/MSNPSharp/Services/StorageServiceWrapper.cs b/MSNPSharp/Services/StorageServiceWrapper.cs new file mode 100644 index 0000000..2a5cff9 --- /dev/null +++ b/MSNPSharp/Services/StorageServiceWrapper.cs @@ -0,0 +1,71 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Sockets; + +namespace MSNPSharp.Services +{ + using MSNPSharp.MSNWS.MSNStorageService; + + [System.Web.Services.WebServiceBindingAttribute(Name = "StorageServiceBinding", Namespace = "http://www.msn.com/webservices/storage/2008")] + internal sealed class StorageServiceWrapper: StorageService + { + private IPEndPoint localEndPoint = null; + + public StorageServiceWrapper() + : base() + { + } + + public StorageServiceWrapper(IPEndPoint localEndPoint) + : base() + { + this.localEndPoint = localEndPoint; + } + + + protected override WebRequest GetWebRequest(Uri uri) + { + WebRequest request = base.GetWebRequest(uri); + if (request is HttpWebRequest) + { + (request as HttpWebRequest).ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint((new IPEndPointCallback(localEndPoint)).BindIPEndPointCallback); + } + + return request; + } + } +} diff --git a/MSNPSharp/Services/WhatsUpService.cs b/MSNPSharp/Services/WhatsUpService.cs new file mode 100644 index 0000000..d71764c --- /dev/null +++ b/MSNPSharp/Services/WhatsUpService.cs @@ -0,0 +1,174 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace MSNPSharp +{ + using MSNPSharp.IO; + using MSNPSharp.Core; + using MSNPSharp.MSNWS.MSNABSharingService; + + public class GetWhatsUpCompletedEventArgs : EventArgs + { + private Exception error = null; + private GetContactsRecentActivityResultType response = null; + + /// + /// InnerException + /// + public Exception Error + { + get + { + return error; + } + } + + public GetContactsRecentActivityResultType Response + { + get + { + return response; + } + } + + protected GetWhatsUpCompletedEventArgs() + { + } + + public GetWhatsUpCompletedEventArgs(Exception err, GetContactsRecentActivityResultType resp) + { + error = err; + response = resp; + } + } + + + public class WhatsUpService : MSNService + { + + private string feedUrl = string.Empty; + + /// + /// RSS feed url for what's up service. + /// + public string FeedUrl + { + get + { + return feedUrl; + } + } + + public event EventHandler GetWhatsUpCompleted; + + + public WhatsUpService(NSMessageHandler nsHandler) + : base(nsHandler) + { + } + + public void GetWhatsUp() + { + GetWhatsUp(50); + } + + /// + /// Get the recent activities of your contacts. + /// + /// Max activity count, must be larger than zero and less than 200. + public void GetWhatsUp(int count) + { + if (count > 200) + { + count = 200; + } + else if (count < 0) + { + count = 50; + } + + if (NSMessageHandler.MSNTicket != MSNTicket.Empty) + { + MsnServiceState getContactsRecentActivityObject = new MsnServiceState(PartnerScenario.None, "GetContactsRecentActivity", true); + WhatsUpServiceBinding wuService = (WhatsUpServiceBinding)CreateService(MsnServiceType.WhatsUp, getContactsRecentActivityObject); + wuService.GetContactsRecentActivityCompleted += delegate(object sender, GetContactsRecentActivityCompletedEventArgs e) + { + OnAfterCompleted(new ServiceOperationEventArgs(wuService, MsnServiceType.WhatsUp, e)); + + if (NSMessageHandler.MSNTicket == MSNTicket.Empty) + return; + + if (e.Cancelled) + return; + + if (e.Error != null) + { + OnGetWhatsUpCompleted(this, new GetWhatsUpCompletedEventArgs(e.Error, null)); + Trace.WriteLineIf(Settings.TraceSwitch.TraceError, e.Error.Message, GetType().Name); + return; + } + + if (e.Result.GetContactsRecentActivityResult != null) + { + feedUrl = e.Result.GetContactsRecentActivityResult.FeedUrl; + OnGetWhatsUpCompleted(this, new GetWhatsUpCompletedEventArgs(null, e.Result.GetContactsRecentActivityResult)); + } + else + { + OnGetWhatsUpCompleted(this, new GetWhatsUpCompletedEventArgs(null, null)); + } + }; + + GetContactsRecentActivityRequestType request = new GetContactsRecentActivityRequestType(); + request.entityHandle = new entityHandle(); + request.entityHandle.Cid = Convert.ToInt64(NSMessageHandler.ContactList.Owner.CID); + request.locales = new string[] { System.Globalization.CultureInfo.CurrentCulture.Name }; + request.count = count; + + RunAsyncMethod(new BeforeRunAsyncMethodEventArgs(wuService, MsnServiceType.WhatsUp, getContactsRecentActivityObject, request)); + } + } + + protected virtual void OnGetWhatsUpCompleted(object sender, GetWhatsUpCompletedEventArgs e) + { + if (GetWhatsUpCompleted != null) + { + GetWhatsUpCompleted(sender, e); + } + } + } +}; diff --git a/MSNPSharp/Services/WhatsUpServiceBindingWrapper.cs b/MSNPSharp/Services/WhatsUpServiceBindingWrapper.cs new file mode 100644 index 0000000..dddd1f9 --- /dev/null +++ b/MSNPSharp/Services/WhatsUpServiceBindingWrapper.cs @@ -0,0 +1,72 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Net; +using System.Net.Sockets; + +namespace MSNPSharp.Services +{ + using MSNPSharp.MSNWS.MSNABSharingService; + + [System.Web.Services.WebServiceBindingAttribute(Name = "WhatsUpServiceBinding", Namespace = "http://www.msn.com/webservices/AddressBook")] + internal sealed class WhatsUpServiceBindingWrapper : WhatsUpServiceBinding + { + private IPEndPoint localEndPoint = null; + + public WhatsUpServiceBindingWrapper() + : base() + { + } + + public WhatsUpServiceBindingWrapper(IPEndPoint localEndPoint) + : base() + { + this.localEndPoint = localEndPoint; + } + + protected override WebRequest GetWebRequest(Uri uri) + { + WebRequest request = base.GetWebRequest(uri); + if (request is HttpWebRequest) + { + (request as HttpWebRequest).ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint((new IPEndPointCallback(localEndPoint)).BindIPEndPointCallback); + } + + return request; + } + + } +} + diff --git a/MSNPSharp/SingleSignOn.cs b/MSNPSharp/SingleSignOn.cs new file mode 100644 index 0000000..7f76baf --- /dev/null +++ b/MSNPSharp/SingleSignOn.cs @@ -0,0 +1,1048 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; +using System.Net; +using System.Xml; +using System.Text; +using System.Threading; +using System.Diagnostics; +using System.Globalization; +using System.Xml.Serialization; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Security.Authentication; +using System.Web.Services.Protocols; +using System.Security.Cryptography.X509Certificates; + +namespace MSNPSharp +{ + using MSNPSharp.MSNWS.MSNSecurityTokenService; + using MSNPSharp.IO; + using MSNPSharp.Services; + + [Flags] + public enum SSOTicketType + { + None = 0x00, + Clear = 0x01, + Contact = 0x02, + OIM = 0x04, + Storage = 0x10, + Web = 0x20, + WhatsUp = 0x40 + } + + public enum ExpiryState + { + NotExpired, + WillExpireSoon, + Expired + } + + #region MSNTicket + + [Serializable] + public sealed class MSNTicket + { + public static readonly MSNTicket Empty = new MSNTicket(null); + + private string policy = "MBI_KEY_OLD"; + private string mainBrandID = "MSFT"; + private string oimLockKey = String.Empty; + private long ownerCID = 0; + + [NonSerialized] + private SerializableDictionary ssoTickets = new SerializableDictionary(); + private SerializableDictionary cacheKeys = new SerializableDictionary(0); + + [NonSerialized] + private int hashcode; + [NonSerialized] + internal int DeleteTick; + + public MSNTicket() + { + } + + internal MSNTicket(Credentials creds) + { + if (creds != null) + { + hashcode = (creds.Account.ToLowerInvariant() + creds.Password).GetHashCode(); + DeleteTick = unchecked(Environment.TickCount + (Settings.MSNTicketLifeTime * 60000)); // in minutes + } + } + + #region Properties + + #region CacheKey + + + private void InitializeCacheKeys() + { + if (!cacheKeys.ContainsKey(CacheKeyType.OmegaContactServiceCacheKey)) + { + cacheKeys.Add(CacheKeyType.OmegaContactServiceCacheKey, String.Empty); + } + + if (!cacheKeys.ContainsKey(CacheKeyType.StorageServiceCacheKey)) + { + cacheKeys.Add(CacheKeyType.StorageServiceCacheKey, String.Empty); + } + } + + /// + /// CacheKeys for webservices. + /// + public SerializableDictionary CacheKeys + { + get + { + InitializeCacheKeys(); + return cacheKeys; + } + set + { + cacheKeys = value; + } + } + + #endregion + + public SerializableDictionary SSOTickets + { + get + { + return ssoTickets; + } + set + { + ssoTickets = value; + } + } + + public string Policy + { + get + { + return policy; + } + set + { + policy = value; + } + } + + public string MainBrandID + { + get + { + return mainBrandID; + } + set + { + mainBrandID = value; + } + } + + public string OIMLockKey + { + get + { + return oimLockKey; + } + set + { + oimLockKey = value; + } + } + + public long OwnerCID + { + get + { + return ownerCID; + } + set + { + ownerCID = value; + } + } + + #endregion + + public ExpiryState Expired(SSOTicketType tt) + { + if (SSOTickets.ContainsKey(tt)) + { + if (SSOTickets[tt].Expires < DateTime.Now) + return ExpiryState.Expired; + + return (SSOTickets[tt].Expires < DateTime.Now.AddSeconds(10)) ? ExpiryState.WillExpireSoon : ExpiryState.NotExpired; + } + return ExpiryState.Expired; + } + + public override int GetHashCode() + { + return hashcode; + } + + public override bool Equals(object obj) + { + if (obj == null || obj.GetType() != GetType()) + return false; + + if (ReferenceEquals(this, obj)) + return true; + + return GetHashCode() == ((MSNTicket)obj).GetHashCode(); + } + } + + #endregion + + #region SSOTicket + + public class SSOTicket + { + private String domain = String.Empty; + private String ticket = String.Empty; + private String binarySecret = String.Empty; + private DateTime created = DateTime.MinValue; + private DateTime expires = DateTime.MinValue; + private SSOTicketType type = SSOTicketType.None; + + internal SSOTicket() + { + } + + public SSOTicket(SSOTicketType tickettype) + { + type = tickettype; + } + + public String Domain + { + get + { + return domain; + } + set + { + domain = value; + } + } + + public String Ticket + { + get + { + return ticket; + } + set + { + ticket = value; + } + } + + public String BinarySecret + { + get + { + return binarySecret; + } + set + { + binarySecret = value; + } + } + + public DateTime Created + { + get + { + return created; + } + set + { + created = value; + } + } + + public DateTime Expires + { + get + { + return expires; + } + set + { + expires = value; + } + } + + public SSOTicketType TicketType + { + get + { + return type; + } + + internal set + { + type = value; + } + } + } + + #endregion + + #region SingleSignOnManager + + internal static class SingleSignOnManager + { + private static Dictionary cache = new Dictionary(); + private static DateTime nextCleanup = NextCleanupTime(); + private static object syncObject; + private static object SyncObject + { + get + { + if (syncObject == null) + { + object newobj = new object(); + Interlocked.CompareExchange(ref syncObject, newobj, null); + } + + return syncObject; + } + } + + private static DateTime NextCleanupTime() + { + return DateTime.Now.AddMinutes(Settings.MSNTicketsCleanupInterval); + } + + private static void CheckCleanup() + { + if (nextCleanup < DateTime.Now) + { + lock (SyncObject) + { + if (nextCleanup < DateTime.Now) + { + nextCleanup = NextCleanupTime(); + int tickcount = Environment.TickCount; + List cachestodelete = new List(); + foreach (MSNTicket t in cache.Values) + { + if (t.DeleteTick != 0 && t.DeleteTick < tickcount) + { + cachestodelete.Add(t.GetHashCode()); + } + } + if (cachestodelete.Count > 0) + { + foreach (int i in cachestodelete) + { + cache.Remove(i); + } + GC.Collect(); + } + } + } + } + } + + internal static void Authenticate( + NSMessageHandler nsMessageHandler, + string policy, + EventHandler onSuccess, + EventHandler onError) + { + CheckCleanup(); + + if (nsMessageHandler != null) + { + int hashcode = (nsMessageHandler.Credentials.Account.ToLowerInvariant() + nsMessageHandler.Credentials.Password).GetHashCode(); + MSNTicket ticket = cache.ContainsKey(hashcode) ? cache[hashcode] : new MSNTicket(nsMessageHandler.Credentials); + SSOTicketType[] ssos = (SSOTicketType[])Enum.GetValues(typeof(SSOTicketType)); + SSOTicketType expiredtickets = SSOTicketType.None; + + foreach (SSOTicketType ssot in ssos) + { + if (ExpiryState.NotExpired != ticket.Expired(ssot)) + expiredtickets |= ssot; + } + + if (expiredtickets == SSOTicketType.None) + { + nsMessageHandler.MSNTicket = ticket; + + if (onSuccess != null) + { + onSuccess(nsMessageHandler, EventArgs.Empty); + } + } + else + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Request new tickets: " + expiredtickets, "SingleSignOnManager"); + + SingleSignOn sso = new SingleSignOn(nsMessageHandler, policy); + sso.AddAuths(expiredtickets); + + if (onSuccess == null && onError == null) + { + sso.Authenticate(ticket, false); + cache[hashcode] = ticket; + nsMessageHandler.MSNTicket = ticket; + } + else + { + try + { + sso.Authenticate(ticket, true, + delegate(object sender, EventArgs e) + { + cache[hashcode] = ticket; + nsMessageHandler.MSNTicket = ticket; + + if (onSuccess != null) + { + onSuccess(nsMessageHandler, e); + } + }, + delegate(object sender, ExceptionEventArgs e) + { + if (onError != null) + { + onError(nsMessageHandler, e); + } + }); + } + catch (Exception error) + { + if (onError != null) + { + onError(nsMessageHandler, new ExceptionEventArgs(error)); + } + } + } + } + } + } + + internal static bool RenewIfExpired(NSMessageHandler nsMessageHandler, SSOTicketType renew) + { + bool renewResult = true; + CheckCleanup(); + + if (nsMessageHandler != null) + { + int hashcode = (nsMessageHandler.Credentials.Account.ToLowerInvariant() + nsMessageHandler.Credentials.Password).GetHashCode(); + MSNTicket ticket = cache.ContainsKey(hashcode) ? cache[hashcode] : new MSNTicket(nsMessageHandler.Credentials); + ExpiryState es = ticket.Expired(renew); + + if (ExpiryState.NotExpired != es) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "Re-new ticket: " + renew, "SingleSignOnManager"); + + SingleSignOn sso = new SingleSignOn(nsMessageHandler, ticket.Policy); + + sso.AddAuths(renew); + + if (es == ExpiryState.WillExpireSoon) + { + sso.Authenticate(ticket, true); + } + else + { + try + { + sso.Authenticate(ticket, false); + } + catch (Exception ex) + { + Trace.WriteLineIf(Settings.TraceSwitch.TraceError + , "Renew failed: " + ex.Message + "\r\n" + ex.StackTrace); + renewResult = false; + } + cache[hashcode] = ticket; + } + } + + nsMessageHandler.MSNTicket = ticket; + } + + return renewResult; + } + } + + #endregion + + #region SingleSignOn + + public class SingleSignOn + { + private string user = string.Empty; + private string pass = string.Empty; + private string policy = string.Empty; + private int authId = 0; + private List auths = new List(0); + private NSMessageHandler nsMessageHandler = null; + + private NSMessageHandler NSMessageHandler + { + get { return nsMessageHandler; } + set + { + nsMessageHandler = value; + } + } + + private WebProxy WebProxy + { + get + { + return NSMessageHandler == null ? null : NSMessageHandler.ConnectivitySettings.WebProxy; + } + } + + private IPEndPoint LocalEndPoint + { + get + { + return NSMessageHandler == null ? null : new IPEndPoint(String.IsNullOrEmpty(NSMessageHandler.ConnectivitySettings.LocalHost) ? IPAddress.Any : IPAddress.Parse(NSMessageHandler.ConnectivitySettings.LocalHost), NSMessageHandler.ConnectivitySettings.LocalPort); + } + } + + + public SingleSignOn(string username, string password, string policy) + { + this.user = username; + this.pass = password; + this.policy = policy; + } + + public SingleSignOn(NSMessageHandler nsHandler, string policy) + : this(nsHandler.Credentials.Account, nsHandler.Credentials.Password, policy) + { + NSMessageHandler = nsHandler; + } + + public void AuthenticationAdd(string domain, string policyref) + { + RequestSecurityTokenType requestToken = new RequestSecurityTokenType(); + requestToken.Id = "RST" + authId.ToString(); + requestToken.RequestType = RequestTypeOpenEnum.httpschemasxmlsoaporgws200502trustIssue; + requestToken.AppliesTo = new AppliesTo(); + requestToken.AppliesTo.EndpointReference = new EndpointReferenceType(); + requestToken.AppliesTo.EndpointReference.Address = new AttributedURIType(); + requestToken.AppliesTo.EndpointReference.Address.Value = domain; + + if (policyref != null) + { + requestToken.PolicyReference = new PolicyReference(); + requestToken.PolicyReference.URI = policyref; + } + + auths.Add(requestToken); + + authId++; + } + + public void AddDefaultAuths() + { + AddAuths(SSOTicketType.Clear | SSOTicketType.Contact | SSOTicketType.OIM | SSOTicketType.Storage | SSOTicketType.Web | SSOTicketType.WhatsUp); + } + + public void AddAuths(SSOTicketType ssott) + { + AuthenticationAdd("http://Passport.NET/tb", null); + + SSOTicketType[] ssos = (SSOTicketType[])Enum.GetValues(typeof(SSOTicketType)); + + foreach (SSOTicketType sso in ssos) + { + switch (sso & ssott) + { + case SSOTicketType.Contact: + AuthenticationAdd("contacts.msn.com", "MBI"); + break; + + case SSOTicketType.OIM: + AuthenticationAdd("messengersecure.live.com", "MBI_SSL"); + break; + + case SSOTicketType.Clear: + AuthenticationAdd("messengerclear.live.com", policy); + break; + + case SSOTicketType.Storage: + AuthenticationAdd("storage.msn.com", "MBI"); + break; + + case SSOTicketType.Web: + AuthenticationAdd("messenger.msn.com", "?id=507"); + break; + + case SSOTicketType.WhatsUp: + AuthenticationAdd("msnmsgr.escargot.chat", "MBI"); + break; + } + } + } + + + public void Authenticate(MSNTicket msnticket, bool async) + { + Authenticate(msnticket, async, null, null); + } + + public void Authenticate(MSNTicket msnticket, bool async, EventHandler onSuccess, EventHandler onError) + { + SecurityTokenService securService = CreateSecurityTokenService(@"http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue", @"HTTPS://msnmsgr.escargot.chat:443//RST2.srf"); + Authenticate(securService, msnticket, async, onSuccess, onError); + } + + public void Authenticate(SecurityTokenService securService, MSNTicket msnticket, bool async, EventHandler onSuccess, EventHandler onError) + { + if (user.Split('@').Length > 1) + { + if (user.Split('@')[1].ToLower(CultureInfo.InvariantCulture) == "msn.com") + { + securService.Url = @"https://msnmsgr.escargot.chat/RST2.srf"; + } + } + else + { + throw new AuthenticationException("Invalid account"); + } + + RequestMultipleSecurityTokensType mulToken = new RequestMultipleSecurityTokensType(); + mulToken.Id = "RSTS"; + mulToken.RequestSecurityToken = auths.ToArray(); + + if (async) + { + securService.RequestMultipleSecurityTokensCompleted += delegate(object sender, RequestMultipleSecurityTokensCompletedEventArgs e) + { + if (!e.Cancelled) + { + + if (e.Error != null) + { + if (ProcessError(securService, e.Error as SoapException, msnticket, async, onSuccess, onError)) return; + + MSNPSharpException sexp = new MSNPSharpException(e.Error.Message + ". See innerexception for detail.", e.Error); + if (securService.pp != null) + sexp.Data["Code"] = securService.pp.reqstatus; //Error code + + if (onError == null) + { + throw sexp; + } + else + { + onError(this, new ExceptionEventArgs(sexp)); + } + + return; + } + + GetTickets(e.Result, securService, msnticket); + + if (onSuccess != null) + { + onSuccess(this, EventArgs.Empty); + } + } + }; + securService.RequestMultipleSecurityTokensAsync(mulToken, new object()); + } + else + { + RequestSecurityTokenResponseType[] result = null; + try + { + result = securService.RequestMultipleSecurityTokens(mulToken); + } + catch (Exception ex) + { + if (ProcessError(securService, ex as SoapException, msnticket, async, onSuccess, onError)) return; + + MSNPSharpException sexp = new MSNPSharpException(ex.Message + ". See innerexception for detail.", ex); + if (securService.pp != null) + sexp.Data["Code"] = securService.pp.reqstatus; //Error code + + throw sexp; + } + + GetTickets(result, securService, msnticket); + } + } + + private bool ProcessError(SecurityTokenService secureService, SoapException exception, MSNTicket msnticket, bool async, EventHandler onSuccess, EventHandler onError) + { + string errFedDirectLogin = @"Direct login to WLID is not allowed for this federated namespace"; + if (exception == null) return false; + if (secureService.pp == null) return false; + + uint errorCode = uint.Parse(secureService.pp.reqstatus.Remove(0, "0x".Length), NumberStyles.HexNumber); + + if (errorCode == 0x800488ee) + { + if (exception.Detail.InnerXml.IndexOf(errFedDirectLogin) != -1) + { + string fedLoginURL = string.Empty; + string fedAuthURL = string.Empty; + string fedBrandName = string.Empty; + + foreach (extPropertyType extProperty in secureService.pp.extProperties) + { + switch (extProperty.Name) + { + case "STSAuthURL": //STS means Security Token Service. + fedLoginURL = extProperty.Value; + break; + case "AuthURL": + fedAuthURL = extProperty.Value; + break; + case "AllowFedUsersWLIDSignIn": //Is it allow to login by MSN ? Not all feduser can log in with a WLM client. + if (!bool.Parse(extProperty.Value)) + return false; + break; + case "FederationBrandName": + fedBrandName = extProperty.Value; + break; + case "IsFederatedNS": + if (!bool.Parse(extProperty.Value)) + return false; + break; + } + } + + if (fedLoginURL == string.Empty) return false; + + Uri fedLoginURI = new Uri(fedLoginURL); + string strFedLoginURI = fedLoginURI.Scheme.ToUpperInvariant() + "://" + fedLoginURI.Host + (fedLoginURI.Scheme.ToLowerInvariant() == "https" ? ":443" : string.Empty) + "/" + fedLoginURI.PathAndQuery; + SecurityTokenService fedSecureService = CreateSecurityTokenService(@"http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue", strFedLoginURI); + fedSecureService.Url = fedLoginURL; + + RequestSecurityTokenType token = new RequestSecurityTokenType(); + token.Id = "RST0"; + token.RequestType = RequestTypeOpenEnum.httpschemasxmlsoaporgws200502trustIssue; + + AppliesTo appliesTo = new AppliesTo(); + appliesTo.EndpointReference = new EndpointReferenceType(); + appliesTo.EndpointReference.Address = new AttributedURIType(); + appliesTo.EndpointReference.Address.Value = strFedLoginURI.Remove(0, @"HTTPS://".Length); + + token.AppliesTo = appliesTo; + + RequestSecurityTokenResponseType response = null; + + if (async) + { + //Async request. + fedSecureService.RequestSecurityTokenCompleted += delegate(object sender, RequestSecurityTokenCompletedEventArgs e) + { + if (!e.Cancelled) + { + if (e.Error != null) + { + MSNPSharpException sexp = new MSNPSharpException(e.Error.Message + ". See innerexception for detail.", e.Error); + + if (onError == null) + { + throw sexp; + } + else + { + onError(this, new ExceptionEventArgs(sexp)); + } + + return; + } + + response = e.Result; + if (response.RequestedSecurityToken == null) return; + if (response.RequestedSecurityToken.Assertion == null) return; + + AssertionType assertion = response.RequestedSecurityToken.Assertion; + secureService = CreateSecurityTokenService(@"http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue", @"HTTPS://msnmsgr.escargot.chat:443//RST2.srf"); + secureService.Security.Assertion = assertion; + + secureService.Security.Timestamp.Created = response.Lifetime.Created; + secureService.Security.Timestamp.Expires = response.Lifetime.Expires; + + Authenticate(secureService, msnticket, async, onSuccess, onError); + } + }; + + fedSecureService.RequestSecurityTokenAsync(token, new object()); + return true; + } + else + { + //Sync request. + try + { + response = fedSecureService.RequestSecurityToken(token); + } + catch (Exception ex) + { + MSNPSharpException sexp = new MSNPSharpException(ex.Message + ". See innerexception for detail.", ex); + + throw sexp; + } + + if (response.RequestedSecurityToken == null) return false; + if (response.RequestedSecurityToken.Assertion == null) return false; + + AssertionType assertion = response.RequestedSecurityToken.Assertion; + secureService = CreateSecurityTokenService(@"http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue", @"HTTPS://msnmsgr.escargot.chat:443//RST2.srf"); + secureService.Security.Assertion = assertion; + Authenticate(secureService, msnticket, async, onSuccess, onError); + return true; + } + } + } + + return false; + + } + + private SecurityTokenService CreateSecurityTokenService(string actionValue, string toValue) + { + SecurityTokenService securService = new SecurityTokenServiceWrapper(LocalEndPoint); + securService.Timeout = 60000; + securService.Proxy = WebProxy; + securService.AuthInfo = new AuthInfoType(); + securService.AuthInfo.Id = "PPAuthInfo"; + securService.AuthInfo.HostingApp = "{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}"; + securService.AuthInfo.BinaryVersion = "5"; + securService.AuthInfo.Cookies = string.Empty; + securService.AuthInfo.UIVersion = "1"; + securService.AuthInfo.RequestParams = "AQAAAAIAAABsYwQAAAAyMDUy"; + + securService.Security = new SecurityHeaderType(); + securService.Security.UsernameToken = new UsernameTokenType(); + securService.Security.UsernameToken.Id = "user"; + securService.Security.UsernameToken.Username = new AttributedString(); + securService.Security.UsernameToken.Username.Value = user; + securService.Security.UsernameToken.Password = new PasswordString(); + securService.Security.UsernameToken.Password.Value = pass; + + DateTime now = DateTime.Now.ToUniversalTime(); + DateTime begin = (new DateTime(1970, 1, 1)); //Already UTC time, no need to convert + TimeSpan span = now - begin; + + securService.Security.Timestamp = new TimestampType(); + securService.Security.Timestamp.Id = "Timestamp"; + securService.Security.Timestamp.Created = new AttributedDateTime(); + securService.Security.Timestamp.Created.Value = XmlConvert.ToString(now, "yyyy-MM-ddTHH:mm:ssZ"); + securService.Security.Timestamp.Expires = new AttributedDateTime(); + securService.Security.Timestamp.Expires.Value = XmlConvert.ToString(now.AddMinutes(Settings.MSNTicketLifeTime), "yyyy-MM-ddTHH:mm:ssZ"); + + securService.MessageID = new AttributedURIType(); + securService.MessageID.Value = ((int)span.TotalSeconds).ToString(); + + securService.ActionValue = new Action(); + securService.ActionValue.MustUnderstand = true; + securService.ActionValue.Value = actionValue; + + securService.ToValue = new To(); + securService.ToValue.MustUnderstand = true; + securService.ToValue.Value = toValue; + + return securService; + } + + private void GetTickets(RequestSecurityTokenResponseType[] result, SecurityTokenService securService, MSNTicket msnticket) + { + if (securService.pp != null) + { + if (securService.pp.credProperties != null) + { + foreach (credPropertyType credproperty in securService.pp.credProperties) + { + if (credproperty.Name == "MainBrandID") + { + msnticket.MainBrandID = credproperty.Value; + } + if (credproperty.Name == "CID" && !String.IsNullOrEmpty(credproperty.Value)) + { + msnticket.OwnerCID = long.Parse(credproperty.Value, NumberStyles.HexNumber); + } + } + } + if (securService.pp.extProperties != null) + { + foreach (extPropertyType extproperty in securService.pp.extProperties) + { + if (extproperty.Name == "CID" && !String.IsNullOrEmpty(extproperty.Value)) + { + msnticket.OwnerCID = long.Parse(extproperty.Value, NumberStyles.HexNumber); + } + } + } + } + + foreach (RequestSecurityTokenResponseType token in result) + { + SSOTicketType ticketype = SSOTicketType.None; + switch (token.AppliesTo.EndpointReference.Address.Value) + { + case "messenger.msn.com": + ticketype = SSOTicketType.Web; + break; + case "messengersecure.live.com": + ticketype = SSOTicketType.OIM; + break; + case "contacts.msn.com": + ticketype = SSOTicketType.Contact; + break; + case "messengerclear.live.com": + ticketype = SSOTicketType.Clear; + break; + case "storage.msn.com": + ticketype = SSOTicketType.Storage; + break; + case "msnmsgr.escargot.chat": + ticketype = SSOTicketType.WhatsUp; + break; + } + + SSOTicket ssoticket = new SSOTicket(ticketype); + if (token.AppliesTo != null) + ssoticket.Domain = token.AppliesTo.EndpointReference.Address.Value; + if (token.RequestedSecurityToken.BinarySecurityToken != null) + ssoticket.Ticket = token.RequestedSecurityToken.BinarySecurityToken.Value; + if (token.RequestedProofToken != null && token.RequestedProofToken.BinarySecret != null) + { + ssoticket.BinarySecret = token.RequestedProofToken.BinarySecret.Value; + } + if (token.Lifetime != null) + { + ssoticket.Created = XmlConvert.ToDateTime(token.Lifetime.Created.Value, "yyyy-MM-ddTHH:mm:ssZ"); + ssoticket.Expires = XmlConvert.ToDateTime(token.Lifetime.Expires.Value, "yyyy-MM-ddTHH:mm:ssZ"); + } + + msnticket.SSOTickets[ticketype] = ssoticket; + } + + } + } + + #endregion + + #region MBI + + /// + /// MBI encrypt algorithm class + /// + public class MBI + { + private byte[] tagMSGRUSRKEY_struct = new byte[28] + { + //uStructHeaderSize = 28 + 0x1c,0x00,0x00,0x00, + + //uCryptMode = 1 + 0x01,0x00,0x00,0x00, + + //uCipherType = 0x6603 + 0x03,0x66,0x00,0x00, + + //uHashType = 0x8004 + 0x04,0x80,0x00,0x00, + + //uIVLen = 8 + 0x08,0x00,0x00,0x00, + + //uHashLen = 20 + 0x14,0x00,0x00,0x00, + + //uCipherLen = 72 + 0x48,0x00,0x00,0x00 + }; + + /// + /// Get the encrypted string + /// + /// The BinarySecret + /// Nonce get from server + /// + public string Encrypt(string key, string nonce) + { + byte[] key1 = Convert.FromBase64String(key); + byte[] key2 = Derive_Key(key1, Encoding.ASCII.GetBytes("WS-SecureConversationSESSION KEY HASH")); + byte[] key3 = Derive_Key(key1, Encoding.ASCII.GetBytes("WS-SecureConversationSESSION KEY ENCRYPTION")); + byte[] hash = (new HMACSHA1(key2)).ComputeHash(Encoding.ASCII.GetBytes(nonce)); + byte[] iv = new byte[8] { 0, 0, 0, 0, 0, 0, 0, 0 }; + RNGCryptoServiceProvider.Create().GetBytes(iv); + byte[] fillbyt = new byte[8] { 8, 8, 8, 8, 8, 8, 8, 8 }; + TripleDES des3 = TripleDES.Create(); + des3.Mode = CipherMode.CBC; + byte[] desinput = CombinByte(Encoding.ASCII.GetBytes(nonce), fillbyt); + byte[] deshash = new byte[72]; + des3.CreateEncryptor(key3, iv).TransformBlock(desinput, 0, desinput.Length, deshash, 0); + return Convert.ToBase64String(CombinByte(CombinByte(CombinByte(tagMSGRUSRKEY_struct, iv), hash), deshash)); + } + + private static byte[] Derive_Key(byte[] key, byte[] magic) + { + HMACSHA1 hmac = new HMACSHA1(key); + byte[] hash1 = hmac.ComputeHash(magic); + byte[] hash2 = hmac.ComputeHash(CombinByte(hash1, magic)); + byte[] hash3 = hmac.ComputeHash(hash1); + byte[] hash4 = hmac.ComputeHash(CombinByte(hash3, magic)); + byte[] outbyt = new byte[4]; + Array.Copy(hash4, outbyt, outbyt.Length); + return CombinByte(hash2, outbyt); + } + + private static byte[] CombinByte(byte[] front, byte[] follow) + { + byte[] byt = new byte[front.Length + follow.Length]; + front.CopyTo(byt, 0); + follow.CopyTo(byt, front.Length); + return byt; + } + } + + #endregion +}; \ No newline at end of file diff --git a/MSNPSharp/StrDictionary.cs b/MSNPSharp/StrDictionary.cs new file mode 100644 index 0000000..e500b77 --- /dev/null +++ b/MSNPSharp/StrDictionary.cs @@ -0,0 +1,164 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace MSNPSharp +{ + /* + * Those classes are needed because Dictionary/Hashtable doesn't guarantee + * that the Add order will be the same loop order (at least on mono) + */ + + public class StrKeyValuePair + { + string key; + string val; + + public StrKeyValuePair(string key, string val) + { + this.key = key; + this.val = val; + } + + public string Key + { + get + { + return key; + } + set + { + key = value; + } + } + + public string Value + { + get + { + return val; + } + set + { + val = value; + } + } + } + + public class StrDictionary : IEnumerable + { + List content; + + public StrDictionary() + { + content = new List(); + } + + /* + * I know, foreach sux, but for this use case it's ok since + * we will only have no more than 10 items + */ + public string this[string key] + { + get + { + foreach (StrKeyValuePair kvp in content) + if (kvp.Key == key) + return kvp.Value; + + return null; + } + set + { + bool found = false; + + foreach (StrKeyValuePair kvp in content) + { + if (kvp.Key == key) + { + kvp.Value = value; + found = true; + } + } + + if (!found) + Add(key, value); + } + } + + public void Add(string key, string val) + { + StrKeyValuePair kvp = new StrKeyValuePair(key, val); + + content.Add(kvp); + } + + public bool ContainsKey(string key) + { + foreach (StrKeyValuePair kvp in content) + if (kvp.Key == key) + return true; + + return false; + } + + public bool Remove(string key) + { + bool found = false; + + List contentClone = new List(content); + foreach (StrKeyValuePair kvp in contentClone) + { + if (kvp.Key == key) + { + content.Remove(kvp); + found = true; + } + } + + return found; + } + + public void Clear() + { + content.Clear(); + } + + public IEnumerator GetEnumerator() + { + return content.GetEnumerator(); + } + } +}; diff --git a/MSNPSharp/TextMessage.cs b/MSNPSharp/TextMessage.cs new file mode 100644 index 0000000..446d199 --- /dev/null +++ b/MSNPSharp/TextMessage.cs @@ -0,0 +1,414 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Web; +using System.Text; +using System.Drawing; +using System.Collections; +using System.Text.RegularExpressions; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + /// + /// Represents a single plain textual message send over a switchboard (conversation). + /// + /// + /// These message objects are dispatched by events. + /// + [Serializable()] + public class TextMessage : NetworkMessage, ICloneable + { + /// + /// The body of the message + /// + public string Text + { + get + { + return text; + } + set + { + text = value; + } + } + + /// + /// + private string text = String.Empty; + + /// + /// The font used in the message. Default is 'Arial' + /// + public string Font + { + get + { + return font; + } + set + { + font = value; + } + } + + /// + /// + private string font = "Arial"; + + /// + /// The color used in the message. Default is black. + /// + public System.Drawing.Color Color + { + get + { + return color; + } + set + { + color = value; + } + } + + /// + /// + private System.Drawing.Color color = Color.Black; + + /// + /// The decorations used in the message. + /// + /// + /// When there are multiple decorations used the values are bitwise OR'ed! + /// Example to check for bold: + /// if((Decorations & MSNTextDecorations.Bold) > 0) .... + /// If you want to use multiple decorations in a new message: + /// textMessage.Decorations = TextDecorations.Underline | TextDecorations.Italic + /// + public TextDecorations Decorations + { + get + { + return decorations; + } + set + { + decorations = value; + } + } + + /// + /// + private TextDecorations decorations = TextDecorations.None; + + /// + /// The charset used in the message. Default is the ANSI charset. + /// + public MessageCharSet CharSet + { + get + { + return charSet; + } + set + { + charSet = value; + } + } + + /// + /// + private MessageCharSet charSet = MessageCharSet.Ansi; + + /// + /// + private bool rightToLeft; + + /// + /// Text is read right-to-left + /// + public bool RightToLeft + { + get + { + return rightToLeft; + } + set + { + rightToLeft = value; + } + } + + /// + /// The (optional) custom nickname of this message + /// + private string customNickname = string.Empty; + + /// + /// The (optional) custom nickname of this message + /// + public string CustomNickname + { + get + { + return customNickname; + } + set + { + customNickname = value; + } + } + + /// + /// Parses the header in the parent message and sets the style properties. + /// + /// + public override void CreateFromParentMessage(NetworkMessage containerMessage) + { + base.CreateFromParentMessage(containerMessage); + + if (ParentMessage == null) + return; + + // we expect a MSGMessage object + MimeMessage MSGMessage = (MimeMessage)ParentMessage; + + // parse the header from the parent message + ParseHeader(MSGMessage.MimeHeader); + } + + /// + /// Sets the Text property. + /// + /// + public override void ParseBytes(byte[] data) + { + // set the text property for easy retrieval + Text = System.Text.Encoding.UTF8.GetString(data); + } + + + /// + /// Gets the style string specifying charset, font, etc. This is used in the MIME header send with a switchboard message. + /// + /// + internal string GetStyleString() + { + StringBuilder builder = new StringBuilder(); + builder.Append("FN=").Append(MSNHttpUtility.UrlEncode(Font.ToString())); + builder.Append("; EF="); + if (((int)Decorations & (int)TextDecorations.Italic) > 0) + builder.Append('I'); + if (((int)Decorations & (int)TextDecorations.Bold) > 0) + builder.Append('B'); + if (((int)Decorations & (int)TextDecorations.Underline) > 0) + builder.Append('U'); + if (((int)Decorations & (int)TextDecorations.Strike) > 0) + builder.Append('S'); + builder.Append("; CO="); + builder.Append(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:x2}", new object[] { Color.B })); + builder.Append(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:x2}", new object[] { Color.G })); + builder.Append(string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:x2}", new object[] { Color.R })); + builder.Append("; CS=").Append(((int)CharSet).ToString(System.Globalization.CultureInfo.InvariantCulture)); + if (rightToLeft) + builder.Append("; RL=1"); + builder.Append("; PF=22"); + + return builder.ToString(); + } + + /// + /// Gets the header with the body appended as a byte array + /// + /// + public override byte[] GetBytes() + { + return System.Text.Encoding.UTF8.GetBytes(Text); + } + + /// + /// Parses the raw header to set the member variables + /// + internal void ParseHeader(StrDictionary mimeHeader) + { + // example header: "X-MMS-IM-Format: FN=Microsoft%20Sans%20Serif; EF=I; CO=000000; CS=0; PF=22" + if (mimeHeader.ContainsKey(MimeHeaderStrings.X_MMS_IM_Format)) + { + string[] fields = mimeHeader[MimeHeaderStrings.X_MMS_IM_Format].Split(';'); + string FNValue = string.Empty; + string EFValue = string.Empty; + string CSValue = string.Empty; + string COValue = string.Empty; + string PFValue = string.Empty; + + foreach (string field in fields) + { + if (field.Trim().IndexOf("FN=") == 0) + { + FNValue = field.Split('=')[1]; + } + + if (field.Trim().IndexOf("EF=") == 0) + { + EFValue = field.Split('=')[1]; + } + + if (field.Trim().IndexOf("CS=") == 0) + { + CSValue = field.Split('=')[1]; + } + + if (field.Trim().IndexOf("CO=") == 0) + { + COValue = field.Split('=')[1]; + } + + if (field.Trim().IndexOf("PF=") == 0) + { + PFValue = field.Split('=')[1]; + } + } + + if (FNValue != string.Empty) + { + Font = HttpUtility.UrlDecode(FNValue); + } + + if (EFValue != string.Empty) + { + Decorations = TextDecorations.None; + string dec = EFValue; + if (dec.IndexOf('I') >= 0) + Decorations |= TextDecorations.Italic; + if (dec.IndexOf('B') >= 0) + Decorations |= TextDecorations.Bold; + if (dec.IndexOf('U') >= 0) + Decorations |= TextDecorations.Underline; + if (dec.IndexOf('S') >= 0) + Decorations |= TextDecorations.Strike; + } + + if (COValue != string.Empty) + { + string color = COValue; + + if (color.Length < 6) + { + for (int i = 0; i < 6 - COValue.Length; i++) + { + color = "0" + color; + } + } + + try + { + if (color.Length >= 6) + Color = System.Drawing.Color.FromArgb( + int.Parse(color.Substring(4, 2), System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture), // R + int.Parse(color.Substring(2, 2), System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture), // G + int.Parse(color.Substring(0, 2), System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture) // B + ); + } + catch (Exception) + { + } + } + + if (CSValue != string.Empty) + { + try + { + CharSet = (MessageCharSet)int.Parse(CSValue, System.Globalization.CultureInfo.InvariantCulture); + } + catch (Exception) + { + } + } + + if (mimeHeader.ContainsKey(MimeHeaderStrings.P4_Context)) + this.customNickname = mimeHeader[MimeHeaderStrings.P4_Context]; + } + } + + /// + /// Basic constructor. + /// + public TextMessage() + { + } + + /// + /// Textual presentation. + /// + /// + public override string ToString() + { + return Text.Replace("\r", "\\r").Replace("\n", "\\n\n"); + } + + + /// + /// Creates a TextMessage with the specified text as message. + /// + /// + /// This leaves all style attributes to their default values. + /// + /// + public TextMessage(string message) + { + Text = message; + } + + #region ICloneable Members + + public object Clone() + { + TextMessage message = new TextMessage(); + message.charSet = this.charSet; + message.color = this.color; + message.customNickname = this.customNickname; + message.decorations = this.decorations; + message.font = this.font; + message.InnerBody = this.InnerBody; + message.rightToLeft = this.rightToLeft; + message.text = this.text; + + return message; + } + + #endregion + + } +}; diff --git a/MSNPSharp/UnauthorizedException.cs b/MSNPSharp/UnauthorizedException.cs new file mode 100644 index 0000000..57adcab --- /dev/null +++ b/MSNPSharp/UnauthorizedException.cs @@ -0,0 +1,86 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.Runtime.Serialization; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + /// + /// Indicates an authentication error with the Nexus service. + /// + /// + /// This exception is thrown when the Nexus service gives back a 401 Unauthorized header. This occurs most likely due to an invalid account or password. + /// + [Serializable()] + public class UnauthorizedException : MSNPSharpException + { + /// + /// Constructor. + /// + public UnauthorizedException() + { + } + + /// + /// Specifies a general exception. + /// + /// A textual presentation of the exception message + public UnauthorizedException(string message) + : base(message) + { + } + + /// + /// Specifies a general exception but which originates from another exception. + /// + /// A textual presentation of the exception message + /// The (inner)exception which caused this exception. For example a SocketException. + public UnauthorizedException(string message, Exception innerException) + : base(message, innerException) + { + } + + /// + /// Serialization constructor. + /// + /// + /// + protected UnauthorizedException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + +}; diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABAddResponseType.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABAddResponseType.datasource new file mode 100644 index 0000000..bf9009a --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABAddResponseType.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.ABAddResponseType, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABContactAddResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABContactAddResponse.datasource new file mode 100644 index 0000000..ed5e495 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABContactAddResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.ABContactAddResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABContactUpdateResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABContactUpdateResponse.datasource new file mode 100644 index 0000000..00bb7d8 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABContactUpdateResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.ABContactUpdateResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABFindAllResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABFindAllResponse.datasource new file mode 100644 index 0000000..ee62c06 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABFindAllResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.ABFindAllResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABFindByContactsResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABFindByContactsResponse.datasource new file mode 100644 index 0000000..3da2dbe --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABFindByContactsResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.ABFindByContactsResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABFindContactsPagedResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABFindContactsPagedResponse.datasource new file mode 100644 index 0000000..63c9547 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABFindContactsPagedResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.ABFindContactsPagedResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABGroupAddResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABGroupAddResponse.datasource new file mode 100644 index 0000000..eed66e3 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABGroupAddResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.ABGroupAddResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABGroupContactAddResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABGroupContactAddResponse.datasource new file mode 100644 index 0000000..3696736 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABGroupContactAddResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.ABGroupContactAddResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABGroupContactDeleteResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABGroupContactDeleteResponse.datasource new file mode 100644 index 0000000..8351083 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABGroupContactDeleteResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.ABGroupContactDeleteResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABGroupDeleteResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABGroupDeleteResponse.datasource new file mode 100644 index 0000000..3e71a4d --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABGroupDeleteResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.ABGroupDeleteResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABGroupUpdateResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABGroupUpdateResponse.datasource new file mode 100644 index 0000000..d29dde0 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ABGroupUpdateResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.ABGroupUpdateResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/AddDynamicItemResponseType.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/AddDynamicItemResponseType.datasource new file mode 100644 index 0000000..568eb9f --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/AddDynamicItemResponseType.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.AddDynamicItemResponseType, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/AddMemberResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/AddMemberResponse.datasource new file mode 100644 index 0000000..b029a90 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/AddMemberResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.AddMemberResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/BreakConnectionResponseType.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/BreakConnectionResponseType.datasource new file mode 100644 index 0000000..457fadb --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/BreakConnectionResponseType.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.BreakConnectionResponseType, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/CreateCircleResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/CreateCircleResponse.datasource new file mode 100644 index 0000000..a5a96e7 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/CreateCircleResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.CreateCircleResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/CreateContactResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/CreateContactResponse.datasource new file mode 100644 index 0000000..4c57faf --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/CreateContactResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.CreateContactResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/DeleteMemberResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/DeleteMemberResponse.datasource new file mode 100644 index 0000000..b00b894 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/DeleteMemberResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.DeleteMemberResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/FindMembershipResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/FindMembershipResponse.datasource new file mode 100644 index 0000000..2873058 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/FindMembershipResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.FindMembershipResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/GetContactsRecentActivityResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/GetContactsRecentActivityResponse.datasource new file mode 100644 index 0000000..c9b957d --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/GetContactsRecentActivityResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.GetContactsRecentActivityResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/ManageWLConnectionResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ManageWLConnectionResponse.datasource new file mode 100644 index 0000000..4a686e5 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/ManageWLConnectionResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNABSharingService.ManageWLConnectionResponse, Web References.MSNWS.MSNABSharingService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/Reference.cs b/MSNPSharp/Web References/MSNWS.MSNABSharingService/Reference.cs new file mode 100644 index 0000000..458b80f --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/Reference.cs @@ -0,0 +1,9444 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +// +// This source code was auto-generated by Microsoft.VSDesigner, Version 4.0.30319.42000. +// +#pragma warning disable 1591 + +namespace MSNPSharp.MSNWS.MSNABSharingService { + using System; + using System.Web.Services; + using System.Diagnostics; + using System.Web.Services.Protocols; + using System.Xml.Serialization; + using System.ComponentModel; + + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Web.Services.WebServiceBindingAttribute(Name="SharingServiceBinding", Namespace="http://www.msn.com/webservices/AddressBook")] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(Annotation[]))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(Membership[]))] + public partial class SharingServiceBinding : System.Web.Services.Protocols.SoapHttpClientProtocol { + + private ABApplicationHeader aBApplicationHeaderValueField; + + private ABAuthHeader aBAuthHeaderValueField; + + private ServiceHeader serviceHeaderValueField; + + private System.Threading.SendOrPostCallback FindMembershipOperationCompleted; + + private System.Threading.SendOrPostCallback AddMemberOperationCompleted; + + private System.Threading.SendOrPostCallback DeleteMemberOperationCompleted; + + private System.Threading.SendOrPostCallback CreateCircleOperationCompleted; + + private bool useDefaultCredentialsSetExplicitly; + + /// + public SharingServiceBinding() { + this.Url = "https://contacts.msn.com/abservice/SharingService.asmx"; + if ((this.IsLocalFileSystemWebService(this.Url) == true)) { + this.UseDefaultCredentials = true; + this.useDefaultCredentialsSetExplicitly = false; + } + else { + this.useDefaultCredentialsSetExplicitly = true; + } + } + + public ABApplicationHeader ABApplicationHeaderValue { + get { + return this.aBApplicationHeaderValueField; + } + set { + this.aBApplicationHeaderValueField = value; + } + } + + public ABAuthHeader ABAuthHeaderValue { + get { + return this.aBAuthHeaderValueField; + } + set { + this.aBAuthHeaderValueField = value; + } + } + + public ServiceHeader ServiceHeaderValue { + get { + return this.serviceHeaderValueField; + } + set { + this.serviceHeaderValueField = value; + } + } + + public new string Url { + get { + return base.Url; + } + set { + if ((((this.IsLocalFileSystemWebService(base.Url) == true) + && (this.useDefaultCredentialsSetExplicitly == false)) + && (this.IsLocalFileSystemWebService(value) == false))) { + base.UseDefaultCredentials = false; + } + base.Url = value; + } + } + + public new bool UseDefaultCredentials { + get { + return base.UseDefaultCredentials; + } + set { + base.UseDefaultCredentials = value; + this.useDefaultCredentialsSetExplicitly = true; + } + } + + /// + public event FindMembershipCompletedEventHandler FindMembershipCompleted; + + /// + public event AddMemberCompletedEventHandler AddMemberCompleted; + + /// + public event DeleteMemberCompletedEventHandler DeleteMemberCompleted; + + /// + public event CreateCircleCompletedEventHandler CreateCircleCompleted; + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/FindMembership", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("FindMembershipResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public FindMembershipResponse FindMembership([System.Xml.Serialization.XmlElementAttribute("FindMembership", Namespace="http://www.msn.com/webservices/AddressBook")] FindMembershipRequestType FindMembership1) { + object[] results = this.Invoke("FindMembership", new object[] { + FindMembership1}); + return ((FindMembershipResponse)(results[0])); + } + + /// + public void FindMembershipAsync(FindMembershipRequestType FindMembership1) { + this.FindMembershipAsync(FindMembership1, null); + } + + /// + public void FindMembershipAsync(FindMembershipRequestType FindMembership1, object userState) { + if ((this.FindMembershipOperationCompleted == null)) { + this.FindMembershipOperationCompleted = new System.Threading.SendOrPostCallback(this.OnFindMembershipOperationCompleted); + } + this.InvokeAsync("FindMembership", new object[] { + FindMembership1}, this.FindMembershipOperationCompleted, userState); + } + + private void OnFindMembershipOperationCompleted(object arg) { + if ((this.FindMembershipCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.FindMembershipCompleted(this, new FindMembershipCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/AddMember", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("AddMemberResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public AddMemberResponse AddMember([System.Xml.Serialization.XmlElementAttribute("AddMember", Namespace="http://www.msn.com/webservices/AddressBook")] AddMemberRequestType AddMember1) { + object[] results = this.Invoke("AddMember", new object[] { + AddMember1}); + return ((AddMemberResponse)(results[0])); + } + + /// + public void AddMemberAsync(AddMemberRequestType AddMember1) { + this.AddMemberAsync(AddMember1, null); + } + + /// + public void AddMemberAsync(AddMemberRequestType AddMember1, object userState) { + if ((this.AddMemberOperationCompleted == null)) { + this.AddMemberOperationCompleted = new System.Threading.SendOrPostCallback(this.OnAddMemberOperationCompleted); + } + this.InvokeAsync("AddMember", new object[] { + AddMember1}, this.AddMemberOperationCompleted, userState); + } + + private void OnAddMemberOperationCompleted(object arg) { + if ((this.AddMemberCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.AddMemberCompleted(this, new AddMemberCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/DeleteMember", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("DeleteMemberResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public DeleteMemberResponse DeleteMember([System.Xml.Serialization.XmlElementAttribute("DeleteMember", Namespace="http://www.msn.com/webservices/AddressBook")] DeleteMemberRequestType DeleteMember1) { + object[] results = this.Invoke("DeleteMember", new object[] { + DeleteMember1}); + return ((DeleteMemberResponse)(results[0])); + } + + /// + public void DeleteMemberAsync(DeleteMemberRequestType DeleteMember1) { + this.DeleteMemberAsync(DeleteMember1, null); + } + + /// + public void DeleteMemberAsync(DeleteMemberRequestType DeleteMember1, object userState) { + if ((this.DeleteMemberOperationCompleted == null)) { + this.DeleteMemberOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDeleteMemberOperationCompleted); + } + this.InvokeAsync("DeleteMember", new object[] { + DeleteMember1}, this.DeleteMemberOperationCompleted, userState); + } + + private void OnDeleteMemberOperationCompleted(object arg) { + if ((this.DeleteMemberCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.DeleteMemberCompleted(this, new DeleteMemberCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/CreateCircle", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("CreateCircleResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public CreateCircleResponse CreateCircle([System.Xml.Serialization.XmlElementAttribute("CreateCircle", Namespace="http://www.msn.com/webservices/AddressBook")] CreateCircleRequestType CreateCircle1) { + object[] results = this.Invoke("CreateCircle", new object[] { + CreateCircle1}); + return ((CreateCircleResponse)(results[0])); + } + + /// + public void CreateCircleAsync(CreateCircleRequestType CreateCircle1) { + this.CreateCircleAsync(CreateCircle1, null); + } + + /// + public void CreateCircleAsync(CreateCircleRequestType CreateCircle1, object userState) { + if ((this.CreateCircleOperationCompleted == null)) { + this.CreateCircleOperationCompleted = new System.Threading.SendOrPostCallback(this.OnCreateCircleOperationCompleted); + } + this.InvokeAsync("CreateCircle", new object[] { + CreateCircle1}, this.CreateCircleOperationCompleted, userState); + } + + private void OnCreateCircleOperationCompleted(object arg) { + if ((this.CreateCircleCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.CreateCircleCompleted(this, new CreateCircleCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + public new void CancelAsync(object userState) { + base.CancelAsync(userState); + } + + private bool IsLocalFileSystemWebService(string url) { + if (((url == null) + || (url == string.Empty))) { + return false; + } + System.Uri wsUri = new System.Uri(url); + if (((wsUri.Port >= 1024) + && (string.Compare(wsUri.Host, "localHost", System.StringComparison.OrdinalIgnoreCase) == 0))) { + return true; + } + return false; + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Web.Services.WebServiceBindingAttribute(Name="ABServiceBinding", Namespace="http://www.msn.com/webservices/AddressBook")] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(Annotation[]))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(Membership[]))] + public partial class ABServiceBinding : System.Web.Services.Protocols.SoapHttpClientProtocol { + + private ABApplicationHeader aBApplicationHeaderValueField; + + private ABAuthHeader aBAuthHeaderValueField; + + private ServiceHeader serviceHeaderValueField; + + private System.Threading.SendOrPostCallback ABFindAllOperationCompleted; + + private System.Threading.SendOrPostCallback ABContactAddOperationCompleted; + + private System.Threading.SendOrPostCallback ABContactDeleteOperationCompleted; + + private System.Threading.SendOrPostCallback ABGroupContactAddOperationCompleted; + + private System.Threading.SendOrPostCallback ABGroupAddOperationCompleted; + + private System.Threading.SendOrPostCallback ABGroupUpdateOperationCompleted; + + private System.Threading.SendOrPostCallback ABGroupDeleteOperationCompleted; + + private System.Threading.SendOrPostCallback ABGroupContactDeleteOperationCompleted; + + private System.Threading.SendOrPostCallback ABContactUpdateOperationCompleted; + + private System.Threading.SendOrPostCallback ABAddOperationCompleted; + + private System.Threading.SendOrPostCallback UpdateDynamicItemOperationCompleted; + + private System.Threading.SendOrPostCallback ABFindContactsPagedOperationCompleted; + + private System.Threading.SendOrPostCallback CreateContactOperationCompleted; + + private System.Threading.SendOrPostCallback ManageWLConnectionOperationCompleted; + + private System.Threading.SendOrPostCallback BreakConnectionOperationCompleted; + + private System.Threading.SendOrPostCallback AddDynamicItemOperationCompleted; + + private System.Threading.SendOrPostCallback ABFindByContactsOperationCompleted; + + private bool useDefaultCredentialsSetExplicitly; + + /// + public ABServiceBinding() { + this.Url = "https://contacts.msn.com/abservice/abservice.asmx"; + if ((this.IsLocalFileSystemWebService(this.Url) == true)) { + this.UseDefaultCredentials = true; + this.useDefaultCredentialsSetExplicitly = false; + } + else { + this.useDefaultCredentialsSetExplicitly = true; + } + } + + public ABApplicationHeader ABApplicationHeaderValue { + get { + return this.aBApplicationHeaderValueField; + } + set { + this.aBApplicationHeaderValueField = value; + } + } + + public ABAuthHeader ABAuthHeaderValue { + get { + return this.aBAuthHeaderValueField; + } + set { + this.aBAuthHeaderValueField = value; + } + } + + public ServiceHeader ServiceHeaderValue { + get { + return this.serviceHeaderValueField; + } + set { + this.serviceHeaderValueField = value; + } + } + + public new string Url { + get { + return base.Url; + } + set { + if ((((this.IsLocalFileSystemWebService(base.Url) == true) + && (this.useDefaultCredentialsSetExplicitly == false)) + && (this.IsLocalFileSystemWebService(value) == false))) { + base.UseDefaultCredentials = false; + } + base.Url = value; + } + } + + public new bool UseDefaultCredentials { + get { + return base.UseDefaultCredentials; + } + set { + base.UseDefaultCredentials = value; + this.useDefaultCredentialsSetExplicitly = true; + } + } + + /// + public event ABFindAllCompletedEventHandler ABFindAllCompleted; + + /// + public event ABContactAddCompletedEventHandler ABContactAddCompleted; + + /// + public event ABContactDeleteCompletedEventHandler ABContactDeleteCompleted; + + /// + public event ABGroupContactAddCompletedEventHandler ABGroupContactAddCompleted; + + /// + public event ABGroupAddCompletedEventHandler ABGroupAddCompleted; + + /// + public event ABGroupUpdateCompletedEventHandler ABGroupUpdateCompleted; + + /// + public event ABGroupDeleteCompletedEventHandler ABGroupDeleteCompleted; + + /// + public event ABGroupContactDeleteCompletedEventHandler ABGroupContactDeleteCompleted; + + /// + public event ABContactUpdateCompletedEventHandler ABContactUpdateCompleted; + + /// + public event ABAddCompletedEventHandler ABAddCompleted; + + /// + public event UpdateDynamicItemCompletedEventHandler UpdateDynamicItemCompleted; + + /// + public event ABFindContactsPagedCompletedEventHandler ABFindContactsPagedCompleted; + + /// + public event CreateContactCompletedEventHandler CreateContactCompleted; + + /// + public event ManageWLConnectionCompletedEventHandler ManageWLConnectionCompleted; + + /// + public event BreakConnectionCompletedEventHandler BreakConnectionCompleted; + + /// + public event AddDynamicItemCompletedEventHandler AddDynamicItemCompleted; + + /// + public event ABFindByContactsCompletedEventHandler ABFindByContactsCompleted; + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/ABFindAll", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ABFindAllResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public ABFindAllResponse ABFindAll([System.Xml.Serialization.XmlElementAttribute("ABFindAll", Namespace="http://www.msn.com/webservices/AddressBook")] ABFindAllRequestType ABFindAll1) { + object[] results = this.Invoke("ABFindAll", new object[] { + ABFindAll1}); + return ((ABFindAllResponse)(results[0])); + } + + /// + public void ABFindAllAsync(ABFindAllRequestType ABFindAll1) { + this.ABFindAllAsync(ABFindAll1, null); + } + + /// + public void ABFindAllAsync(ABFindAllRequestType ABFindAll1, object userState) { + if ((this.ABFindAllOperationCompleted == null)) { + this.ABFindAllOperationCompleted = new System.Threading.SendOrPostCallback(this.OnABFindAllOperationCompleted); + } + this.InvokeAsync("ABFindAll", new object[] { + ABFindAll1}, this.ABFindAllOperationCompleted, userState); + } + + private void OnABFindAllOperationCompleted(object arg) { + if ((this.ABFindAllCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ABFindAllCompleted(this, new ABFindAllCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/ABContactAdd", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ABContactAddResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public ABContactAddResponse ABContactAdd([System.Xml.Serialization.XmlElementAttribute("ABContactAdd", Namespace="http://www.msn.com/webservices/AddressBook")] ABContactAddRequestType ABContactAdd1) { + object[] results = this.Invoke("ABContactAdd", new object[] { + ABContactAdd1}); + return ((ABContactAddResponse)(results[0])); + } + + /// + public void ABContactAddAsync(ABContactAddRequestType ABContactAdd1) { + this.ABContactAddAsync(ABContactAdd1, null); + } + + /// + public void ABContactAddAsync(ABContactAddRequestType ABContactAdd1, object userState) { + if ((this.ABContactAddOperationCompleted == null)) { + this.ABContactAddOperationCompleted = new System.Threading.SendOrPostCallback(this.OnABContactAddOperationCompleted); + } + this.InvokeAsync("ABContactAdd", new object[] { + ABContactAdd1}, this.ABContactAddOperationCompleted, userState); + } + + private void OnABContactAddOperationCompleted(object arg) { + if ((this.ABContactAddCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ABContactAddCompleted(this, new ABContactAddCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/ABContactDelete", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ABContactDeleteResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public object ABContactDelete([System.Xml.Serialization.XmlElementAttribute("ABContactDelete", Namespace="http://www.msn.com/webservices/AddressBook")] ABContactDeleteRequestType ABContactDelete1) { + object[] results = this.Invoke("ABContactDelete", new object[] { + ABContactDelete1}); + return ((object)(results[0])); + } + + /// + public void ABContactDeleteAsync(ABContactDeleteRequestType ABContactDelete1) { + this.ABContactDeleteAsync(ABContactDelete1, null); + } + + /// + public void ABContactDeleteAsync(ABContactDeleteRequestType ABContactDelete1, object userState) { + if ((this.ABContactDeleteOperationCompleted == null)) { + this.ABContactDeleteOperationCompleted = new System.Threading.SendOrPostCallback(this.OnABContactDeleteOperationCompleted); + } + this.InvokeAsync("ABContactDelete", new object[] { + ABContactDelete1}, this.ABContactDeleteOperationCompleted, userState); + } + + private void OnABContactDeleteOperationCompleted(object arg) { + if ((this.ABContactDeleteCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ABContactDeleteCompleted(this, new ABContactDeleteCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/ABGroupContactAdd", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ABGroupContactAddResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public ABGroupContactAddResponse ABGroupContactAdd([System.Xml.Serialization.XmlElementAttribute("ABGroupContactAdd", Namespace="http://www.msn.com/webservices/AddressBook")] ABGroupContactAddRequestType ABGroupContactAdd1) { + object[] results = this.Invoke("ABGroupContactAdd", new object[] { + ABGroupContactAdd1}); + return ((ABGroupContactAddResponse)(results[0])); + } + + /// + public void ABGroupContactAddAsync(ABGroupContactAddRequestType ABGroupContactAdd1) { + this.ABGroupContactAddAsync(ABGroupContactAdd1, null); + } + + /// + public void ABGroupContactAddAsync(ABGroupContactAddRequestType ABGroupContactAdd1, object userState) { + if ((this.ABGroupContactAddOperationCompleted == null)) { + this.ABGroupContactAddOperationCompleted = new System.Threading.SendOrPostCallback(this.OnABGroupContactAddOperationCompleted); + } + this.InvokeAsync("ABGroupContactAdd", new object[] { + ABGroupContactAdd1}, this.ABGroupContactAddOperationCompleted, userState); + } + + private void OnABGroupContactAddOperationCompleted(object arg) { + if ((this.ABGroupContactAddCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ABGroupContactAddCompleted(this, new ABGroupContactAddCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/ABGroupAdd", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ABGroupAddResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public ABGroupAddResponse ABGroupAdd([System.Xml.Serialization.XmlElementAttribute("ABGroupAdd", Namespace="http://www.msn.com/webservices/AddressBook")] ABGroupAddRequestType ABGroupAdd1) { + object[] results = this.Invoke("ABGroupAdd", new object[] { + ABGroupAdd1}); + return ((ABGroupAddResponse)(results[0])); + } + + /// + public void ABGroupAddAsync(ABGroupAddRequestType ABGroupAdd1) { + this.ABGroupAddAsync(ABGroupAdd1, null); + } + + /// + public void ABGroupAddAsync(ABGroupAddRequestType ABGroupAdd1, object userState) { + if ((this.ABGroupAddOperationCompleted == null)) { + this.ABGroupAddOperationCompleted = new System.Threading.SendOrPostCallback(this.OnABGroupAddOperationCompleted); + } + this.InvokeAsync("ABGroupAdd", new object[] { + ABGroupAdd1}, this.ABGroupAddOperationCompleted, userState); + } + + private void OnABGroupAddOperationCompleted(object arg) { + if ((this.ABGroupAddCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ABGroupAddCompleted(this, new ABGroupAddCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/ABGroupUpdate", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ABGroupUpdateResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public ABGroupUpdateResponse ABGroupUpdate([System.Xml.Serialization.XmlElementAttribute("ABGroupUpdate", Namespace="http://www.msn.com/webservices/AddressBook")] ABGroupUpdateRequestType ABGroupUpdate1) { + object[] results = this.Invoke("ABGroupUpdate", new object[] { + ABGroupUpdate1}); + return ((ABGroupUpdateResponse)(results[0])); + } + + /// + public void ABGroupUpdateAsync(ABGroupUpdateRequestType ABGroupUpdate1) { + this.ABGroupUpdateAsync(ABGroupUpdate1, null); + } + + /// + public void ABGroupUpdateAsync(ABGroupUpdateRequestType ABGroupUpdate1, object userState) { + if ((this.ABGroupUpdateOperationCompleted == null)) { + this.ABGroupUpdateOperationCompleted = new System.Threading.SendOrPostCallback(this.OnABGroupUpdateOperationCompleted); + } + this.InvokeAsync("ABGroupUpdate", new object[] { + ABGroupUpdate1}, this.ABGroupUpdateOperationCompleted, userState); + } + + private void OnABGroupUpdateOperationCompleted(object arg) { + if ((this.ABGroupUpdateCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ABGroupUpdateCompleted(this, new ABGroupUpdateCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/ABGroupDelete", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ABGroupDeleteResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public ABGroupDeleteResponse ABGroupDelete([System.Xml.Serialization.XmlElementAttribute("ABGroupDelete", Namespace="http://www.msn.com/webservices/AddressBook")] ABGroupDeleteRequestType ABGroupDelete1) { + object[] results = this.Invoke("ABGroupDelete", new object[] { + ABGroupDelete1}); + return ((ABGroupDeleteResponse)(results[0])); + } + + /// + public void ABGroupDeleteAsync(ABGroupDeleteRequestType ABGroupDelete1) { + this.ABGroupDeleteAsync(ABGroupDelete1, null); + } + + /// + public void ABGroupDeleteAsync(ABGroupDeleteRequestType ABGroupDelete1, object userState) { + if ((this.ABGroupDeleteOperationCompleted == null)) { + this.ABGroupDeleteOperationCompleted = new System.Threading.SendOrPostCallback(this.OnABGroupDeleteOperationCompleted); + } + this.InvokeAsync("ABGroupDelete", new object[] { + ABGroupDelete1}, this.ABGroupDeleteOperationCompleted, userState); + } + + private void OnABGroupDeleteOperationCompleted(object arg) { + if ((this.ABGroupDeleteCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ABGroupDeleteCompleted(this, new ABGroupDeleteCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/ABGroupContactDelete", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ABGroupContactDeleteResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public ABGroupContactDeleteResponse ABGroupContactDelete([System.Xml.Serialization.XmlElementAttribute("ABGroupContactDelete", Namespace="http://www.msn.com/webservices/AddressBook")] ABGroupContactDeleteRequestType ABGroupContactDelete1) { + object[] results = this.Invoke("ABGroupContactDelete", new object[] { + ABGroupContactDelete1}); + return ((ABGroupContactDeleteResponse)(results[0])); + } + + /// + public void ABGroupContactDeleteAsync(ABGroupContactDeleteRequestType ABGroupContactDelete1) { + this.ABGroupContactDeleteAsync(ABGroupContactDelete1, null); + } + + /// + public void ABGroupContactDeleteAsync(ABGroupContactDeleteRequestType ABGroupContactDelete1, object userState) { + if ((this.ABGroupContactDeleteOperationCompleted == null)) { + this.ABGroupContactDeleteOperationCompleted = new System.Threading.SendOrPostCallback(this.OnABGroupContactDeleteOperationCompleted); + } + this.InvokeAsync("ABGroupContactDelete", new object[] { + ABGroupContactDelete1}, this.ABGroupContactDeleteOperationCompleted, userState); + } + + private void OnABGroupContactDeleteOperationCompleted(object arg) { + if ((this.ABGroupContactDeleteCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ABGroupContactDeleteCompleted(this, new ABGroupContactDeleteCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/ABContactUpdate", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ABContactUpdateResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public ABContactUpdateResponse ABContactUpdate([System.Xml.Serialization.XmlElementAttribute("ABContactUpdate", Namespace="http://www.msn.com/webservices/AddressBook")] ABContactUpdateRequestType ABContactUpdate1) { + object[] results = this.Invoke("ABContactUpdate", new object[] { + ABContactUpdate1}); + return ((ABContactUpdateResponse)(results[0])); + } + + /// + public void ABContactUpdateAsync(ABContactUpdateRequestType ABContactUpdate1) { + this.ABContactUpdateAsync(ABContactUpdate1, null); + } + + /// + public void ABContactUpdateAsync(ABContactUpdateRequestType ABContactUpdate1, object userState) { + if ((this.ABContactUpdateOperationCompleted == null)) { + this.ABContactUpdateOperationCompleted = new System.Threading.SendOrPostCallback(this.OnABContactUpdateOperationCompleted); + } + this.InvokeAsync("ABContactUpdate", new object[] { + ABContactUpdate1}, this.ABContactUpdateOperationCompleted, userState); + } + + private void OnABContactUpdateOperationCompleted(object arg) { + if ((this.ABContactUpdateCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ABContactUpdateCompleted(this, new ABContactUpdateCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/ABAdd", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ABAddResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public ABAddResponseType ABAdd([System.Xml.Serialization.XmlElementAttribute("ABAdd", Namespace="http://www.msn.com/webservices/AddressBook")] ABAddRequestType ABAdd1) { + object[] results = this.Invoke("ABAdd", new object[] { + ABAdd1}); + return ((ABAddResponseType)(results[0])); + } + + /// + public void ABAddAsync(ABAddRequestType ABAdd1) { + this.ABAddAsync(ABAdd1, null); + } + + /// + public void ABAddAsync(ABAddRequestType ABAdd1, object userState) { + if ((this.ABAddOperationCompleted == null)) { + this.ABAddOperationCompleted = new System.Threading.SendOrPostCallback(this.OnABAddOperationCompleted); + } + this.InvokeAsync("ABAdd", new object[] { + ABAdd1}, this.ABAddOperationCompleted, userState); + } + + private void OnABAddOperationCompleted(object arg) { + if ((this.ABAddCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ABAddCompleted(this, new ABAddCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/UpdateDynamicItem", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("UpdateDynamicItemResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public object UpdateDynamicItem([System.Xml.Serialization.XmlElementAttribute("UpdateDynamicItem", Namespace="http://www.msn.com/webservices/AddressBook")] UpdateDynamicItemRequestType UpdateDynamicItem1) { + object[] results = this.Invoke("UpdateDynamicItem", new object[] { + UpdateDynamicItem1}); + return ((object)(results[0])); + } + + /// + public void UpdateDynamicItemAsync(UpdateDynamicItemRequestType UpdateDynamicItem1) { + this.UpdateDynamicItemAsync(UpdateDynamicItem1, null); + } + + /// + public void UpdateDynamicItemAsync(UpdateDynamicItemRequestType UpdateDynamicItem1, object userState) { + if ((this.UpdateDynamicItemOperationCompleted == null)) { + this.UpdateDynamicItemOperationCompleted = new System.Threading.SendOrPostCallback(this.OnUpdateDynamicItemOperationCompleted); + } + this.InvokeAsync("UpdateDynamicItem", new object[] { + UpdateDynamicItem1}, this.UpdateDynamicItemOperationCompleted, userState); + } + + private void OnUpdateDynamicItemOperationCompleted(object arg) { + if ((this.UpdateDynamicItemCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.UpdateDynamicItemCompleted(this, new UpdateDynamicItemCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/ABFindContactsPaged", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ABFindContactsPagedResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public ABFindContactsPagedResponse ABFindContactsPaged([System.Xml.Serialization.XmlElementAttribute("ABFindContactsPaged", Namespace="http://www.msn.com/webservices/AddressBook")] ABFindContactsPagedRequestType ABFindContactsPaged1) { + object[] results = this.Invoke("ABFindContactsPaged", new object[] { + ABFindContactsPaged1}); + return ((ABFindContactsPagedResponse)(results[0])); + } + + /// + public void ABFindContactsPagedAsync(ABFindContactsPagedRequestType ABFindContactsPaged1) { + this.ABFindContactsPagedAsync(ABFindContactsPaged1, null); + } + + /// + public void ABFindContactsPagedAsync(ABFindContactsPagedRequestType ABFindContactsPaged1, object userState) { + if ((this.ABFindContactsPagedOperationCompleted == null)) { + this.ABFindContactsPagedOperationCompleted = new System.Threading.SendOrPostCallback(this.OnABFindContactsPagedOperationCompleted); + } + this.InvokeAsync("ABFindContactsPaged", new object[] { + ABFindContactsPaged1}, this.ABFindContactsPagedOperationCompleted, userState); + } + + private void OnABFindContactsPagedOperationCompleted(object arg) { + if ((this.ABFindContactsPagedCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ABFindContactsPagedCompleted(this, new ABFindContactsPagedCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/CreateContact", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("CreateContactResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public CreateContactResponse CreateContact([System.Xml.Serialization.XmlElementAttribute("CreateContact", Namespace="http://www.msn.com/webservices/AddressBook")] CreateContactType CreateContact1) { + object[] results = this.Invoke("CreateContact", new object[] { + CreateContact1}); + return ((CreateContactResponse)(results[0])); + } + + /// + public void CreateContactAsync(CreateContactType CreateContact1) { + this.CreateContactAsync(CreateContact1, null); + } + + /// + public void CreateContactAsync(CreateContactType CreateContact1, object userState) { + if ((this.CreateContactOperationCompleted == null)) { + this.CreateContactOperationCompleted = new System.Threading.SendOrPostCallback(this.OnCreateContactOperationCompleted); + } + this.InvokeAsync("CreateContact", new object[] { + CreateContact1}, this.CreateContactOperationCompleted, userState); + } + + private void OnCreateContactOperationCompleted(object arg) { + if ((this.CreateContactCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.CreateContactCompleted(this, new CreateContactCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/ManageWLConnection", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ManageWLConnectionResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public ManageWLConnectionResponse ManageWLConnection([System.Xml.Serialization.XmlElementAttribute("ManageWLConnection", Namespace="http://www.msn.com/webservices/AddressBook")] ManageWLConnectionRequestType ManageWLConnection1) { + object[] results = this.Invoke("ManageWLConnection", new object[] { + ManageWLConnection1}); + return ((ManageWLConnectionResponse)(results[0])); + } + + /// + public void ManageWLConnectionAsync(ManageWLConnectionRequestType ManageWLConnection1) { + this.ManageWLConnectionAsync(ManageWLConnection1, null); + } + + /// + public void ManageWLConnectionAsync(ManageWLConnectionRequestType ManageWLConnection1, object userState) { + if ((this.ManageWLConnectionOperationCompleted == null)) { + this.ManageWLConnectionOperationCompleted = new System.Threading.SendOrPostCallback(this.OnManageWLConnectionOperationCompleted); + } + this.InvokeAsync("ManageWLConnection", new object[] { + ManageWLConnection1}, this.ManageWLConnectionOperationCompleted, userState); + } + + private void OnManageWLConnectionOperationCompleted(object arg) { + if ((this.ManageWLConnectionCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ManageWLConnectionCompleted(this, new ManageWLConnectionCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/BreakConnection", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("BreakConnectionResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public BreakConnectionResponseType BreakConnection([System.Xml.Serialization.XmlElementAttribute("BreakConnection", Namespace="http://www.msn.com/webservices/AddressBook")] BreakConnectionRequestType BreakConnection1) { + object[] results = this.Invoke("BreakConnection", new object[] { + BreakConnection1}); + return ((BreakConnectionResponseType)(results[0])); + } + + /// + public void BreakConnectionAsync(BreakConnectionRequestType BreakConnection1) { + this.BreakConnectionAsync(BreakConnection1, null); + } + + /// + public void BreakConnectionAsync(BreakConnectionRequestType BreakConnection1, object userState) { + if ((this.BreakConnectionOperationCompleted == null)) { + this.BreakConnectionOperationCompleted = new System.Threading.SendOrPostCallback(this.OnBreakConnectionOperationCompleted); + } + this.InvokeAsync("BreakConnection", new object[] { + BreakConnection1}, this.BreakConnectionOperationCompleted, userState); + } + + private void OnBreakConnectionOperationCompleted(object arg) { + if ((this.BreakConnectionCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.BreakConnectionCompleted(this, new BreakConnectionCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/AddDynamicItem", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("AddDynamicItemResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public AddDynamicItemResponseType AddDynamicItem([System.Xml.Serialization.XmlElementAttribute("AddDynamicItem", Namespace="http://www.msn.com/webservices/AddressBook")] AddDynamicItemRequestType AddDynamicItem1) { + object[] results = this.Invoke("AddDynamicItem", new object[] { + AddDynamicItem1}); + return ((AddDynamicItemResponseType)(results[0])); + } + + /// + public void AddDynamicItemAsync(AddDynamicItemRequestType AddDynamicItem1) { + this.AddDynamicItemAsync(AddDynamicItem1, null); + } + + /// + public void AddDynamicItemAsync(AddDynamicItemRequestType AddDynamicItem1, object userState) { + if ((this.AddDynamicItemOperationCompleted == null)) { + this.AddDynamicItemOperationCompleted = new System.Threading.SendOrPostCallback(this.OnAddDynamicItemOperationCompleted); + } + this.InvokeAsync("AddDynamicItem", new object[] { + AddDynamicItem1}, this.AddDynamicItemOperationCompleted, userState); + } + + private void OnAddDynamicItemOperationCompleted(object arg) { + if ((this.AddDynamicItemCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.AddDynamicItemCompleted(this, new AddDynamicItemCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("ServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ABAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/ABFindByContacts", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ABFindByContactsResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public ABFindByContactsResponse ABFindByContacts([System.Xml.Serialization.XmlElementAttribute("ABFindByContacts", Namespace="http://www.msn.com/webservices/AddressBook")] ABFindByContactsRequestType ABFindByContacts1) { + object[] results = this.Invoke("ABFindByContacts", new object[] { + ABFindByContacts1}); + return ((ABFindByContactsResponse)(results[0])); + } + + /// + public void ABFindByContactsAsync(ABFindByContactsRequestType ABFindByContacts1) { + this.ABFindByContactsAsync(ABFindByContacts1, null); + } + + /// + public void ABFindByContactsAsync(ABFindByContactsRequestType ABFindByContacts1, object userState) { + if ((this.ABFindByContactsOperationCompleted == null)) { + this.ABFindByContactsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnABFindByContactsOperationCompleted); + } + this.InvokeAsync("ABFindByContacts", new object[] { + ABFindByContacts1}, this.ABFindByContactsOperationCompleted, userState); + } + + private void OnABFindByContactsOperationCompleted(object arg) { + if ((this.ABFindByContactsCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ABFindByContactsCompleted(this, new ABFindByContactsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + public new void CancelAsync(object userState) { + base.CancelAsync(userState); + } + + private bool IsLocalFileSystemWebService(string url) { + if (((url == null) + || (url == string.Empty))) { + return false; + } + System.Uri wsUri = new System.Uri(url); + if (((wsUri.Port >= 1024) + && (string.Compare(wsUri.Host, "localHost", System.StringComparison.OrdinalIgnoreCase) == 0))) { + return true; + } + return false; + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Web.Services.WebServiceBindingAttribute(Name="WhatsUpServiceBinding", Namespace="http://www.msn.com/webservices/AddressBook")] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(Annotation[]))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(Membership[]))] + public partial class WhatsUpServiceBinding : System.Web.Services.Protocols.SoapHttpClientProtocol { + + private WNApplicationHeader wNApplicationHeaderValueField; + + private WNAuthHeader wNAuthHeaderValueField; + + private WNServiceHeader wNServiceHeaderValueField; + + private System.Threading.SendOrPostCallback GetContactsRecentActivityOperationCompleted; + + private bool useDefaultCredentialsSetExplicitly; + + /// + public WhatsUpServiceBinding() { + this.Url = "http://msnmsgr.escargot.chat/whatsnew/whatsnewservice.asmx"; + if ((this.IsLocalFileSystemWebService(this.Url) == true)) { + this.UseDefaultCredentials = true; + this.useDefaultCredentialsSetExplicitly = false; + } + else { + this.useDefaultCredentialsSetExplicitly = true; + } + } + + public WNApplicationHeader WNApplicationHeaderValue { + get { + return this.wNApplicationHeaderValueField; + } + set { + this.wNApplicationHeaderValueField = value; + } + } + + public WNAuthHeader WNAuthHeaderValue { + get { + return this.wNAuthHeaderValueField; + } + set { + this.wNAuthHeaderValueField = value; + } + } + + public WNServiceHeader WNServiceHeaderValue { + get { + return this.wNServiceHeaderValueField; + } + set { + this.wNServiceHeaderValueField = value; + } + } + + public new string Url { + get { + return base.Url; + } + set { + if ((((this.IsLocalFileSystemWebService(base.Url) == true) + && (this.useDefaultCredentialsSetExplicitly == false)) + && (this.IsLocalFileSystemWebService(value) == false))) { + base.UseDefaultCredentials = false; + } + base.Url = value; + } + } + + public new bool UseDefaultCredentials { + get { + return base.UseDefaultCredentials; + } + set { + base.UseDefaultCredentials = value; + this.useDefaultCredentialsSetExplicitly = true; + } + } + + /// + public event GetContactsRecentActivityCompletedEventHandler GetContactsRecentActivityCompleted; + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("WNApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("WNServiceHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("WNAuthHeaderValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/AddressBook/GetContactsRecentActivity", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("GetContactsRecentActivityResponse", Namespace="http://www.msn.com/webservices/AddressBook")] + public GetContactsRecentActivityResponse GetContactsRecentActivity([System.Xml.Serialization.XmlElementAttribute("GetContactsRecentActivity", Namespace="http://www.msn.com/webservices/AddressBook")] GetContactsRecentActivityRequestType GetContactsRecentActivity1) { + object[] results = this.Invoke("GetContactsRecentActivity", new object[] { + GetContactsRecentActivity1}); + return ((GetContactsRecentActivityResponse)(results[0])); + } + + /// + public void GetContactsRecentActivityAsync(GetContactsRecentActivityRequestType GetContactsRecentActivity1) { + this.GetContactsRecentActivityAsync(GetContactsRecentActivity1, null); + } + + /// + public void GetContactsRecentActivityAsync(GetContactsRecentActivityRequestType GetContactsRecentActivity1, object userState) { + if ((this.GetContactsRecentActivityOperationCompleted == null)) { + this.GetContactsRecentActivityOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetContactsRecentActivityOperationCompleted); + } + this.InvokeAsync("GetContactsRecentActivity", new object[] { + GetContactsRecentActivity1}, this.GetContactsRecentActivityOperationCompleted, userState); + } + + private void OnGetContactsRecentActivityOperationCompleted(object arg) { + if ((this.GetContactsRecentActivityCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.GetContactsRecentActivityCompleted(this, new GetContactsRecentActivityCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + public new void CancelAsync(object userState) { + base.CancelAsync(userState); + } + + private bool IsLocalFileSystemWebService(string url) { + if (((url == null) + || (url == string.Empty))) { + return false; + } + System.Uri wsUri = new System.Uri(url); + if (((wsUri.Port >= 1024) + && (string.Compare(wsUri.Host, "localHost", System.StringComparison.OrdinalIgnoreCase) == 0))) { + return true; + } + return false; + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.msn.com/webservices/AddressBook", IsNullable=false)] + public partial class ABAuthHeader : System.Web.Services.Protocols.SoapHeader { + + private bool managedGroupRequestField; + + private string ticketTokenField; + + public ABAuthHeader() { + this.managedGroupRequestField = false; + } + + /// + public bool ManagedGroupRequest { + get { + return this.managedGroupRequestField; + } + set { + this.managedGroupRequestField = value; + } + } + + /// + public string TicketToken { + get { + return this.ticketTokenField; + } + set { + this.ticketTokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class AddDynamicItemResponseType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class AddDynamicItemRequestType { + + private string abIdField; + + private BaseDynamicItemType[] dynamicItemsField; + + /// + public string abId { + get { + return this.abIdField; + } + set { + this.abIdField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("DynamicItem", IsNullable=false)] + public BaseDynamicItemType[] dynamicItems { + get { + return this.dynamicItemsField; + } + set { + this.dynamicItemsField = value; + } + } + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(PassportDynamicItem))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(CircleDynamicItem))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class BaseDynamicItemType { + + private string typeField; + + private bool deletedField; + + private bool deletedFieldSpecified; + + private string lastChangedField; + + private NotificationDataType[] notificationsField; + + private string changesField; + + /// + public string Type { + get { + return this.typeField; + } + set { + this.typeField = value; + } + } + + /// + public bool Deleted { + get { + return this.deletedField; + } + set { + this.deletedField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool DeletedSpecified { + get { + return this.deletedFieldSpecified; + } + set { + this.deletedFieldSpecified = value; + } + } + + /// + public string LastChanged { + get { + return this.lastChangedField; + } + set { + this.lastChangedField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("NotificationData", IsNullable=false)] + public NotificationDataType[] Notifications { + get { + return this.notificationsField; + } + set { + this.notificationsField = value; + } + } + + /// + public string Changes { + get { + return this.changesField; + } + set { + this.changesField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class NotificationDataType { + + private ServiceType storeServiceField; + + private string statusField; + + private string lastChangedField; + + private bool gleamField; + + private string instanceIdField; + + public NotificationDataType() { + this.gleamField = false; + this.instanceIdField = "0"; + } + + /// + public ServiceType StoreService { + get { + return this.storeServiceField; + } + set { + this.storeServiceField = value; + } + } + + /// + public string Status { + get { + return this.statusField; + } + set { + this.statusField = value; + } + } + + /// + public string LastChanged { + get { + return this.lastChangedField; + } + set { + this.lastChangedField = value; + } + } + + /// + public bool Gleam { + get { + return this.gleamField; + } + set { + this.gleamField = value; + } + } + + /// + public string InstanceId { + get { + return this.instanceIdField; + } + set { + this.instanceIdField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ServiceType { + + private Membership[] membershipsField; + + private InfoType infoField; + + private string changesField; + + private string lastChangeField; + + private bool deletedField; + + public ServiceType() { + this.lastChangeField = "0001-01-01T00:00:00"; + this.deletedField = false; + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)] + public Membership[] Memberships { + get { + return this.membershipsField; + } + set { + this.membershipsField = value; + } + } + + /// + public InfoType Info { + get { + return this.infoField; + } + set { + this.infoField = value; + } + } + + /// + public string Changes { + get { + return this.changesField; + } + set { + this.changesField = value; + } + } + + /// + public string LastChange { + get { + return this.lastChangeField; + } + set { + this.lastChangeField = value; + } + } + + /// + public bool Deleted { + get { + return this.deletedField; + } + set { + this.deletedField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class Membership { + + private string memberRoleField; + + private BaseMember[] membersField; + + private bool membershipIsCompleteField; + + private bool membershipIsCompleteFieldSpecified; + + /// + public string MemberRole { + get { + return this.memberRoleField; + } + set { + this.memberRoleField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Member", IsNullable=false)] + public BaseMember[] Members { + get { + return this.membersField; + } + set { + this.membersField = value; + } + } + + /// + public bool MembershipIsComplete { + get { + return this.membershipIsCompleteField; + } + set { + this.membershipIsCompleteField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool MembershipIsCompleteSpecified { + get { + return this.membershipIsCompleteFieldSpecified; + } + set { + this.membershipIsCompleteFieldSpecified = value; + } + } + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ExternalIDMember))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GroupMember))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(PartnerMember))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(EveryoneMember))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DomainMember))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ServiceMember))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(RoleMember))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(PhoneMember))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(EmailMember))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(PassportMember))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(CircleMember))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class BaseMember { + + private string membershipIdField; + + private string typeField; + + private BaseMemberLocation locationField; + + private string displayNameField; + + private MemberState stateField; + + private Annotation[] annotationsField; + + private bool deletedField; + + private string lastChangedField; + + private string joinedDateField; + + private string expirationDateField; + + private string changesField; + + public BaseMember() { + this.deletedField = false; + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="positiveInteger")] + public string MembershipId { + get { + return this.membershipIdField; + } + set { + this.membershipIdField = value; + } + } + + /// + public string Type { + get { + return this.typeField; + } + set { + this.typeField = value; + } + } + + /// + public BaseMemberLocation Location { + get { + return this.locationField; + } + set { + this.locationField = value; + } + } + + /// + public string DisplayName { + get { + return this.displayNameField; + } + set { + this.displayNameField = value; + } + } + + /// + public MemberState State { + get { + return this.stateField; + } + set { + this.stateField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)] + public Annotation[] Annotations { + get { + return this.annotationsField; + } + set { + this.annotationsField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(false)] + public bool Deleted { + get { + return this.deletedField; + } + set { + this.deletedField = value; + } + } + + /// + public string LastChanged { + get { + return this.lastChangedField; + } + set { + this.lastChangedField = value; + } + } + + /// + public string JoinedDate { + get { + return this.joinedDateField; + } + set { + this.joinedDateField = value; + } + } + + /// + public string ExpirationDate { + get { + return this.expirationDateField; + } + set { + this.expirationDateField = value; + } + } + + /// + public string Changes { + get { + return this.changesField; + } + set { + this.changesField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class BaseMemberLocation { + + private string idField; + + private bool isPassportNameHiddenField; + + private long cIDField; + + /// + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + public bool IsPassportNameHidden { + get { + return this.isPassportNameHiddenField; + } + set { + this.isPassportNameHiddenField = value; + } + } + + /// + public long CID { + get { + return this.cIDField; + } + set { + this.cIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public enum MemberState { + + /// + Accepted, + + /// + Pending, + + /// + Removed, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class Annotation { + + private string nameField; + + private string valueField; + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ExternalIDMember : BaseMember { + + private string sourceIDField; + + private string objectIDField; + + /// + public string SourceID { + get { + return this.sourceIDField; + } + set { + this.sourceIDField = value; + } + } + + /// + public string ObjectID { + get { + return this.objectIDField; + } + set { + this.objectIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class GroupMember : BaseMember { + + private string idField; + + /// + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class PartnerMember : BaseMember { + + private long appIdField; + + private string scopeField; + + /// + public long AppId { + get { + return this.appIdField; + } + set { + this.appIdField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string Scope { + get { + return this.scopeField; + } + set { + this.scopeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class EveryoneMember : BaseMember { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class DomainMember : BaseMember { + + private string domainNameField; + + /// + public string DomainName { + get { + return this.domainNameField; + } + set { + this.domainNameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ServiceMember : BaseMember { + + private HandleType serviceField; + + /// + public HandleType Service { + get { + return this.serviceField; + } + set { + this.serviceField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class HandleType { + + private string idField; + + private string typeField; + + private string foreignIdField; + + public HandleType() { + this.typeField = "Messenger"; + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + public string Type { + get { + return this.typeField; + } + set { + this.typeField = value; + } + } + + /// + public string ForeignId { + get { + return this.foreignIdField; + } + set { + this.foreignIdField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class RoleMember : BaseMember { + + private string idField; + + private RoleMemberDefiningService definingServiceField; + + private string maxRoleRecursionDepthField; + + private string maxDegreesSeparationField; + + /// + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + public RoleMemberDefiningService DefiningService { + get { + return this.definingServiceField; + } + set { + this.definingServiceField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string MaxRoleRecursionDepth { + get { + return this.maxRoleRecursionDepthField; + } + set { + this.maxRoleRecursionDepthField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string MaxDegreesSeparation { + get { + return this.maxDegreesSeparationField; + } + set { + this.maxDegreesSeparationField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class RoleMemberDefiningService { + + private string idField; + + private string typeField; + + private string foreignIdField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + public string Type { + get { + return this.typeField; + } + set { + this.typeField = value; + } + } + + /// + public string ForeignId { + get { + return this.foreignIdField; + } + set { + this.foreignIdField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class PhoneMember : BaseMember { + + private string phoneNumberField; + + /// + public string PhoneNumber { + get { + return this.phoneNumberField; + } + set { + this.phoneNumberField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class EmailMember : BaseMember { + + private string emailField; + + /// + public string Email { + get { + return this.emailField; + } + set { + this.emailField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class PassportMember : BaseMember { + + private string passportNameField; + + private bool isPassportNameHiddenField; + + private bool isPassportNameHiddenFieldSpecified; + + private int passportIdField; + + private bool passportIdFieldSpecified; + + private long cIDField; + + private bool cIDFieldSpecified; + + private string passportChangesField; + + /// + public string PassportName { + get { + return this.passportNameField; + } + set { + this.passportNameField = value; + } + } + + /// + public bool IsPassportNameHidden { + get { + return this.isPassportNameHiddenField; + } + set { + this.isPassportNameHiddenField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IsPassportNameHiddenSpecified { + get { + return this.isPassportNameHiddenFieldSpecified; + } + set { + this.isPassportNameHiddenFieldSpecified = value; + } + } + + /// + public int PassportId { + get { + return this.passportIdField; + } + set { + this.passportIdField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PassportIdSpecified { + get { + return this.passportIdFieldSpecified; + } + set { + this.passportIdFieldSpecified = value; + } + } + + /// + public long CID { + get { + return this.cIDField; + } + set { + this.cIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool CIDSpecified { + get { + return this.cIDFieldSpecified; + } + set { + this.cIDFieldSpecified = value; + } + } + + /// + public string PassportChanges { + get { + return this.passportChangesField; + } + set { + this.passportChangesField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class CircleMember : BaseMember { + + private string circleIdField; + + /// + public string CircleId { + get { + return this.circleIdField; + } + set { + this.circleIdField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class InfoType { + + private HandleType handleField; + + private string displayNameField; + + private bool inverseRequiredField; + + private string authorizationCriteriaField; + + private string rSSUrlField; + + private bool isBotField; + + public InfoType() { + this.inverseRequiredField = false; + this.isBotField = false; + } + + /// + public HandleType Handle { + get { + return this.handleField; + } + set { + this.handleField = value; + } + } + + /// + public string DisplayName { + get { + return this.displayNameField; + } + set { + this.displayNameField = value; + } + } + + /// + public bool InverseRequired { + get { + return this.inverseRequiredField; + } + set { + this.inverseRequiredField = value; + } + } + + /// + public string AuthorizationCriteria { + get { + return this.authorizationCriteriaField; + } + set { + this.authorizationCriteriaField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="anyURI")] + public string RSSUrl { + get { + return this.rSSUrlField; + } + set { + this.rSSUrlField = value; + } + } + + /// + public bool IsBot { + get { + return this.isBotField; + } + set { + this.isBotField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class PassportDynamicItem : BaseDynamicItemType { + + private string cIDField; + + private string passportNameField; + + private string passportIdField; + + private string spaceStatusField; + + private string spaceLastChangedField; + + private string spaceLastViewedField; + + private bool spaceGleamField; + + private bool spaceGleamFieldSpecified; + + private string profileLastChangedField; + + private string profileLastViewField; + + private string profileStatusField; + + private bool profileGleamField; + + private bool profileGleamFieldSpecified; + + private string contactProfileStatusField; + + private string contactProfileLastChangedField; + + private string contactProfileLastViewedField; + + private string liveContactLastChangedField; + + /// + public string CID { + get { + return this.cIDField; + } + set { + this.cIDField = value; + } + } + + /// + public string PassportName { + get { + return this.passportNameField; + } + set { + this.passportNameField = value; + } + } + + /// + public string PassportId { + get { + return this.passportIdField; + } + set { + this.passportIdField = value; + } + } + + /// + public string SpaceStatus { + get { + return this.spaceStatusField; + } + set { + this.spaceStatusField = value; + } + } + + /// + public string SpaceLastChanged { + get { + return this.spaceLastChangedField; + } + set { + this.spaceLastChangedField = value; + } + } + + /// + public string SpaceLastViewed { + get { + return this.spaceLastViewedField; + } + set { + this.spaceLastViewedField = value; + } + } + + /// + public bool SpaceGleam { + get { + return this.spaceGleamField; + } + set { + this.spaceGleamField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool SpaceGleamSpecified { + get { + return this.spaceGleamFieldSpecified; + } + set { + this.spaceGleamFieldSpecified = value; + } + } + + /// + public string ProfileLastChanged { + get { + return this.profileLastChangedField; + } + set { + this.profileLastChangedField = value; + } + } + + /// + public string ProfileLastView { + get { + return this.profileLastViewField; + } + set { + this.profileLastViewField = value; + } + } + + /// + public string ProfileStatus { + get { + return this.profileStatusField; + } + set { + this.profileStatusField = value; + } + } + + /// + public bool ProfileGleam { + get { + return this.profileGleamField; + } + set { + this.profileGleamField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ProfileGleamSpecified { + get { + return this.profileGleamFieldSpecified; + } + set { + this.profileGleamFieldSpecified = value; + } + } + + /// + public string ContactProfileStatus { + get { + return this.contactProfileStatusField; + } + set { + this.contactProfileStatusField = value; + } + } + + /// + public string ContactProfileLastChanged { + get { + return this.contactProfileLastChangedField; + } + set { + this.contactProfileLastChangedField = value; + } + } + + /// + public string ContactProfileLastViewed { + get { + return this.contactProfileLastViewedField; + } + set { + this.contactProfileLastViewedField = value; + } + } + + /// + public string LiveContactLastChanged { + get { + return this.liveContactLastChangedField; + } + set { + this.liveContactLastChangedField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class CircleDynamicItem : BaseDynamicItemType { + + private string idField; + + /// + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class BreakConnectionResponseType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class BreakConnectionRequestType { + + private abHandleType abHandleField; + + private string contactIdField; + + private bool deleteContactField; + + private bool blockContactField; + + /// + public abHandleType abHandle { + get { + return this.abHandleField; + } + set { + this.abHandleField = value; + } + } + + /// + public string contactId { + get { + return this.contactIdField; + } + set { + this.contactIdField = value; + } + } + + /// + public bool deleteContact { + get { + return this.deleteContactField; + } + set { + this.deleteContactField = value; + } + } + + /// + public bool blockContact { + get { + return this.blockContactField; + } + set { + this.blockContactField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class abHandleType { + + private string aBIdField; + + private long puidField; + + private long cidField; + + /// + public string ABId { + get { + return this.aBIdField; + } + set { + this.aBIdField = value; + } + } + + /// + public long Puid { + get { + return this.puidField; + } + set { + this.puidField = value; + } + } + + /// + public long Cid { + get { + return this.cidField; + } + set { + this.cidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class CreateCircleResponseType { + + private string idField; + + /// + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class CreateContactType { + + private abHandleType abHandleField; + + private contactHandleType contactHandleField; + + /// + public abHandleType abHandle { + get { + return this.abHandleField; + } + set { + this.abHandleField = value; + } + } + + /// + public contactHandleType contactHandle { + get { + return this.contactHandleField; + } + set { + this.contactHandleField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class contactHandleType { + + private string emailField; + + private long puidField; + + private long cidField; + + private string circleIdField; + + /// + public string Email { + get { + return this.emailField; + } + set { + this.emailField = value; + } + } + + /// + public long Puid { + get { + return this.puidField; + } + set { + this.puidField = value; + } + } + + /// + public long Cid { + get { + return this.cidField; + } + set { + this.cidField = value; + } + } + + /// + public string CircleId { + get { + return this.circleIdField; + } + set { + this.circleIdField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ManageWLConnectionRequestType { + + private abHandleType abHandleField; + + private string contactIdField; + + private bool connectionField; + + private bool presenceField; + + private int actionField; + + private int relationshipTypeField; + + private int relationshipRoleField; + + private Annotation[] annotationsField; + + /// + public abHandleType abHandle { + get { + return this.abHandleField; + } + set { + this.abHandleField = value; + } + } + + /// + public string contactId { + get { + return this.contactIdField; + } + set { + this.contactIdField = value; + } + } + + /// + public bool connection { + get { + return this.connectionField; + } + set { + this.connectionField = value; + } + } + + /// + public bool presence { + get { + return this.presenceField; + } + set { + this.presenceField = value; + } + } + + /// + public int action { + get { + return this.actionField; + } + set { + this.actionField = value; + } + } + + /// + public int relationshipType { + get { + return this.relationshipTypeField; + } + set { + this.relationshipTypeField = value; + } + } + + /// + public int relationshipRole { + get { + return this.relationshipRoleField; + } + set { + this.relationshipRoleField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)] + public Annotation[] annotations { + get { + return this.annotationsField; + } + set { + this.annotationsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class GetContactsRecentActivityResultType { + + private ActivityDetailsType[] activitiesField; + + private RecentActivityTemplateContainerType[] templatesField; + + private string feedUrlField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("ActivityDetails", IsNullable=false)] + public ActivityDetailsType[] Activities { + get { + return this.activitiesField; + } + set { + this.activitiesField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("RecentActivityTemplateContainer", IsNullable=false)] + public RecentActivityTemplateContainerType[] Templates { + get { + return this.templatesField; + } + set { + this.templatesField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="anyURI")] + public string FeedUrl { + get { + return this.feedUrlField; + } + set { + this.feedUrlField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ActivityDetailsType { + + private string ownerCIDField; + + private string objectIdField; + + private string applicationIdField; + + private string changeTypeField; + + private string publishDateField; + + private TemplateVariableBaseType[] templateVariablesField; + + private string activityIDField; + + private bool canPublishCommentsField; + + private bool canPublishCommentsFieldSpecified; + + private string visibilityHintField; + + private RelevanceInfoType relevanceInfoField; + + /// + public string OwnerCID { + get { + return this.ownerCIDField; + } + set { + this.ownerCIDField = value; + } + } + + /// + public string ObjectId { + get { + return this.objectIdField; + } + set { + this.objectIdField = value; + } + } + + /// + public string ApplicationId { + get { + return this.applicationIdField; + } + set { + this.applicationIdField = value; + } + } + + /// + public string ChangeType { + get { + return this.changeTypeField; + } + set { + this.changeTypeField = value; + } + } + + /// + public string PublishDate { + get { + return this.publishDateField; + } + set { + this.publishDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("TemplateVariable", IsNullable=false)] + public TemplateVariableBaseType[] TemplateVariables { + get { + return this.templateVariablesField; + } + set { + this.templateVariablesField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="ID")] + public string ActivityID { + get { + return this.activityIDField; + } + set { + this.activityIDField = value; + } + } + + /// + public bool CanPublishComments { + get { + return this.canPublishCommentsField; + } + set { + this.canPublishCommentsField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool CanPublishCommentsSpecified { + get { + return this.canPublishCommentsFieldSpecified; + } + set { + this.canPublishCommentsFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string VisibilityHint { + get { + return this.visibilityHintField; + } + set { + this.visibilityHintField = value; + } + } + + /// + public RelevanceInfoType RelevanceInfo { + get { + return this.relevanceInfoField; + } + set { + this.relevanceInfoField = value; + } + } + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ListTemplateVariable))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(PublisherIdTemplateVariable))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(TargetIdTemplateVariable))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(SimpleTemplateVariableBaseType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ImageTemplateVariable))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(HlinkTemplateVariable))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(TextTemplateVariable))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class TemplateVariableBaseType { + + private string nameField; + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ListTemplateVariable : TemplateVariableBaseType { + + private ListTemplateVariableItemType[] itemsField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("ListTemplateVariableItem", IsNullable=false)] + public ListTemplateVariableItemType[] Items { + get { + return this.itemsField; + } + set { + this.itemsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ListTemplateVariableItemType { + + private SimpleTemplateVariableBaseType[] valuesField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Value", IsNullable=false)] + public SimpleTemplateVariableBaseType[] Values { + get { + return this.valuesField; + } + set { + this.valuesField = value; + } + } + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ImageTemplateVariable))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(HlinkTemplateVariable))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(TextTemplateVariable))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class SimpleTemplateVariableBaseType : TemplateVariableBaseType { + + private string valueField; + + /// + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ImageTemplateVariable : SimpleTemplateVariableBaseType { + + private string hrefField; + + private NotationType[] notationsField; + + private string hrefAsSafeLinkField; + + private string altTextField; + + private string targetMediaTypeField; + + private string targetMediaSourceField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="anyURI")] + public string Href { + get { + return this.hrefField; + } + set { + this.hrefField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Notation", IsNullable=false)] + public NotationType[] Notations { + get { + return this.notationsField; + } + set { + this.notationsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="anyURI")] + public string HrefAsSafeLink { + get { + return this.hrefAsSafeLinkField; + } + set { + this.hrefAsSafeLinkField = value; + } + } + + /// + public string AltText { + get { + return this.altTextField; + } + set { + this.altTextField = value; + } + } + + /// + public string TargetMediaType { + get { + return this.targetMediaTypeField; + } + set { + this.targetMediaTypeField = value; + } + } + + /// + public string TargetMediaSource { + get { + return this.targetMediaSourceField; + } + set { + this.targetMediaSourceField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class NotationType { + + private string nameField; + + private string valueField; + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class HlinkTemplateVariable : SimpleTemplateVariableBaseType { + + private string textField; + + private NotationType[] notationsField; + + private string valueAsSafeLinkField; + + /// + public string Text { + get { + return this.textField; + } + set { + this.textField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Notation", IsNullable=false)] + public NotationType[] Notations { + get { + return this.notationsField; + } + set { + this.notationsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="anyURI")] + public string ValueAsSafeLink { + get { + return this.valueAsSafeLinkField; + } + set { + this.valueAsSafeLinkField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class TextTemplateVariable : SimpleTemplateVariableBaseType { + + private TextTemplateVariableSafeLinks safeLinksField; + + /// + public TextTemplateVariableSafeLinks SafeLinks { + get { + return this.safeLinksField; + } + set { + this.safeLinksField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class TextTemplateVariableSafeLinks { + + private SafeLinkDetailsType safeLinkDetailsField; + + /// + public SafeLinkDetailsType SafeLinkDetails { + get { + return this.safeLinkDetailsField; + } + set { + this.safeLinkDetailsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class SafeLinkDetailsType { + + private string offsetField; + + private string lengthField; + + private string safeUrlField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string Offset { + get { + return this.offsetField; + } + set { + this.offsetField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string Length { + get { + return this.lengthField; + } + set { + this.lengthField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="anyURI")] + public string SafeUrl { + get { + return this.safeUrlField; + } + set { + this.safeUrlField = value; + } + } + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(TargetIdTemplateVariable))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class PublisherIdTemplateVariable : TemplateVariableBaseType { + + private string idField; + + private string nameHintField; + + private string lastNameHintField; + + private bool isFavoriteField; + + private bool isFavoriteFieldSpecified; + + /// + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + public string NameHint { + get { + return this.nameHintField; + } + set { + this.nameHintField = value; + } + } + + /// + public string LastNameHint { + get { + return this.lastNameHintField; + } + set { + this.lastNameHintField = value; + } + } + + /// + public bool IsFavorite { + get { + return this.isFavoriteField; + } + set { + this.isFavoriteField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IsFavoriteSpecified { + get { + return this.isFavoriteFieldSpecified; + } + set { + this.isFavoriteFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class TargetIdTemplateVariable : PublisherIdTemplateVariable { + + private string idOwnerField; + + /// + public string IdOwner { + get { + return this.idOwnerField; + } + set { + this.idOwnerField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class RelevanceInfoType { + + private double timeWeightedScoreField; + + /// + public double TimeWeightedScore { + get { + return this.timeWeightedScoreField; + } + set { + this.timeWeightedScoreField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class RecentActivityTemplateContainerType { + + private string applicationIdField; + + private string applicationNameField; + + private string changeTypeField; + + private string localeField; + + private string[] requestedLocalesField; + + private string templateRevisionField; + + private RecentActivityTemplateType[] templatesField; + + private string[] collapseConditionField; + + /// + public string ApplicationId { + get { + return this.applicationIdField; + } + set { + this.applicationIdField = value; + } + } + + /// + public string ApplicationName { + get { + return this.applicationNameField; + } + set { + this.applicationNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string ChangeType { + get { + return this.changeTypeField; + } + set { + this.changeTypeField = value; + } + } + + /// + public string Locale { + get { + return this.localeField; + } + set { + this.localeField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)] + public string[] RequestedLocales { + get { + return this.requestedLocalesField; + } + set { + this.requestedLocalesField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string TemplateRevision { + get { + return this.templateRevisionField; + } + set { + this.templateRevisionField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("RecentActivityTemplate", IsNullable=false)] + public RecentActivityTemplateType[] Templates { + get { + return this.templatesField; + } + set { + this.templatesField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)] + public string[] CollapseCondition { + get { + return this.collapseConditionField; + } + set { + this.collapseConditionField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class RecentActivityTemplateType { + + private string cardinalityField; + + private string dataField; + + private string titleField; + + /// + public string Cardinality { + get { + return this.cardinalityField; + } + set { + this.cardinalityField = value; + } + } + + /// + public string Data { + get { + return this.dataField; + } + set { + this.dataField = value; + } + } + + /// + public string Title { + get { + return this.titleField; + } + set { + this.titleField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class GetContactsRecentActivityRequestType { + + private entityHandle entityHandleField; + + private string[] localesField; + + private int countField; + + /// + public entityHandle entityHandle { + get { + return this.entityHandleField; + } + set { + this.entityHandleField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)] + public string[] locales { + get { + return this.localesField; + } + set { + this.localesField = value; + } + } + + /// + public int count { + get { + return this.countField; + } + set { + this.countField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class entityHandle { + + private long cidField; + + /// + public long Cid { + get { + return this.cidField; + } + set { + this.cidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABFindContactsPagedResultType { + + private GroupType[] groupsField; + + private ContactType[] contactsField; + + private CircleResultType circleResultField; + + private ABFindContactsPagedResultTypeAB abField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Group", IsNullable=false)] + public GroupType[] Groups { + get { + return this.groupsField; + } + set { + this.groupsField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Contact", IsNullable=false)] + public ContactType[] Contacts { + get { + return this.contactsField; + } + set { + this.contactsField = value; + } + } + + /// + public CircleResultType CircleResult { + get { + return this.circleResultField; + } + set { + this.circleResultField = value; + } + } + + /// + public ABFindContactsPagedResultTypeAB Ab { + get { + return this.abField; + } + set { + this.abField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class GroupType { + + private string groupIdField; + + private groupInfoType groupInfoField; + + private string propertiesChangedField; + + private bool fDeletedField; + + private bool fDeletedFieldSpecified; + + private string lastChangeField; + + /// + public string groupId { + get { + return this.groupIdField; + } + set { + this.groupIdField = value; + } + } + + /// + public groupInfoType groupInfo { + get { + return this.groupInfoField; + } + set { + this.groupInfoField = value; + } + } + + /// + public string propertiesChanged { + get { + return this.propertiesChangedField; + } + set { + this.propertiesChangedField = value; + } + } + + /// + public bool fDeleted { + get { + return this.fDeletedField; + } + set { + this.fDeletedField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool fDeletedSpecified { + get { + return this.fDeletedFieldSpecified; + } + set { + this.fDeletedFieldSpecified = value; + } + } + + /// + public string lastChange { + get { + return this.lastChangeField; + } + set { + this.lastChangeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class groupInfoType { + + private Annotation[] annotationsField; + + private string groupTypeField; + + private string nameField; + + private bool isNotMobileVisibleField; + + private bool isNotMobileVisibleFieldSpecified; + + private bool isPrivateField; + + private bool isPrivateFieldSpecified; + + private bool isFavoriteField; + + private bool isFavoriteFieldSpecified; + + private bool fMessengerField; + + private bool fMessengerFieldSpecified; + + public groupInfoType() { + this.groupTypeField = "C8529CE2-6EAD-434d-881F-341E17DB3FF8"; + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)] + public Annotation[] annotations { + get { + return this.annotationsField; + } + set { + this.annotationsField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute("C8529CE2-6EAD-434d-881F-341E17DB3FF8")] + public string groupType { + get { + return this.groupTypeField; + } + set { + this.groupTypeField = value; + } + } + + /// + public string name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + public bool IsNotMobileVisible { + get { + return this.isNotMobileVisibleField; + } + set { + this.isNotMobileVisibleField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IsNotMobileVisibleSpecified { + get { + return this.isNotMobileVisibleFieldSpecified; + } + set { + this.isNotMobileVisibleFieldSpecified = value; + } + } + + /// + public bool IsPrivate { + get { + return this.isPrivateField; + } + set { + this.isPrivateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IsPrivateSpecified { + get { + return this.isPrivateFieldSpecified; + } + set { + this.isPrivateFieldSpecified = value; + } + } + + /// + public bool IsFavorite { + get { + return this.isFavoriteField; + } + set { + this.isFavoriteField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IsFavoriteSpecified { + get { + return this.isFavoriteFieldSpecified; + } + set { + this.isFavoriteFieldSpecified = value; + } + } + + /// + public bool fMessenger { + get { + return this.fMessengerField; + } + set { + this.fMessengerField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool fMessengerSpecified { + get { + return this.fMessengerFieldSpecified; + } + set { + this.fMessengerFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ContactType { + + private string contactIdField; + + private contactInfoType contactInfoField; + + private string propertiesChangedField; + + private bool fDeletedField; + + private bool fDeletedFieldSpecified; + + private string lastChangeField; + + private string createDateField; + + private string lastModifiedByField; + + private string createdByField; + + /// + public string contactId { + get { + return this.contactIdField; + } + set { + this.contactIdField = value; + } + } + + /// + public contactInfoType contactInfo { + get { + return this.contactInfoField; + } + set { + this.contactInfoField = value; + } + } + + /// + public string propertiesChanged { + get { + return this.propertiesChangedField; + } + set { + this.propertiesChangedField = value; + } + } + + /// + public bool fDeleted { + get { + return this.fDeletedField; + } + set { + this.fDeletedField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool fDeletedSpecified { + get { + return this.fDeletedFieldSpecified; + } + set { + this.fDeletedFieldSpecified = value; + } + } + + /// + public string lastChange { + get { + return this.lastChangeField; + } + set { + this.lastChangeField = value; + } + } + + /// + public string CreateDate { + get { + return this.createDateField; + } + set { + this.createDateField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string LastModifiedBy { + get { + return this.lastModifiedByField; + } + set { + this.lastModifiedByField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string CreatedBy { + get { + return this.createdByField; + } + set { + this.createdByField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class contactInfoType { + + private contactEmailType[] emailsField; + + private contactPhoneType[] phonesField; + + private contactLocationType[] locationsField; + + private contactWebSiteType[] webSitesField; + + private Annotation[] annotationsField; + + private string[] groupIdsField; + + private string[] groupIdsDeletedField; + + private string contactTypeField; + + private string quickNameField; + + private string firstNameField; + + private string middleNameField; + + private string lastNameField; + + private string suffixField; + + private string nameTitleField; + + private string passportNameField; + + private string displayNameField; + + private long puidField; + + private bool puidFieldSpecified; + + private long cIDField; + + private bool cIDFieldSpecified; + + private object brandIdListField; + + private string commentField; + + private bool isMobileIMEnabledField; + + private bool isMobileIMEnabledFieldSpecified; + + private bool isMessengerUserField; + + private bool isMessengerUserFieldSpecified; + + private bool isFavoriteField; + + private bool isFavoriteFieldSpecified; + + private bool isSmtpField; + + private bool isSmtpFieldSpecified; + + private bool hasSpaceField; + + private bool hasSpaceFieldSpecified; + + private string spotWatchStateField; + + private string birthdateField; + + private ContactEmailTypeType primaryEmailTypeField; + + private bool primaryEmailTypeFieldSpecified; + + private ContactLocationTypeType primaryLocationField; + + private bool primaryLocationFieldSpecified; + + private string primaryPhoneField; + + private bool isPrivateField; + + private bool isPrivateFieldSpecified; + + private string anniversaryField; + + private string genderField; + + private string timeZoneField; + + private int trustLevelField; + + private bool trustLevelFieldSpecified; + + private NetworkInfoType[] networkInfoListField; + + private string publicDisplayNameField; + + private bool isAutoUpdateDisabledField; + + private bool isAutoUpdateDisabledFieldSpecified; + + private bool isHiddenField; + + private bool isHiddenFieldSpecified; + + private bool isPassportNameHiddenField; + + private bool isPassportNameHiddenFieldSpecified; + + private bool isNotMobileVisibleField; + + private bool isNotMobileVisibleFieldSpecified; + + private bool isShellContactField; + + private bool isShellContactFieldSpecified; + + private MessengerMemberInfo messengerMemberInfoField; + + private object propertiesChangedField; + + private string clientErrorDataField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("ContactEmail", IsNullable=false)] + public contactEmailType[] emails { + get { + return this.emailsField; + } + set { + this.emailsField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("ContactPhone", IsNullable=false)] + public contactPhoneType[] phones { + get { + return this.phonesField; + } + set { + this.phonesField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("ContactLocation", IsNullable=false)] + public contactLocationType[] locations { + get { + return this.locationsField; + } + set { + this.locationsField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("ContactWebSite", IsNullable=false)] + public contactWebSiteType[] webSites { + get { + return this.webSitesField; + } + set { + this.webSitesField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)] + public Annotation[] annotations { + get { + return this.annotationsField; + } + set { + this.annotationsField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("guid", IsNullable=false)] + public string[] groupIds { + get { + return this.groupIdsField; + } + set { + this.groupIdsField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("guid", IsNullable=false)] + public string[] groupIdsDeleted { + get { + return this.groupIdsDeletedField; + } + set { + this.groupIdsDeletedField = value; + } + } + + /// + public string contactType { + get { + return this.contactTypeField; + } + set { + this.contactTypeField = value; + } + } + + /// + public string quickName { + get { + return this.quickNameField; + } + set { + this.quickNameField = value; + } + } + + /// + public string firstName { + get { + return this.firstNameField; + } + set { + this.firstNameField = value; + } + } + + /// + public string MiddleName { + get { + return this.middleNameField; + } + set { + this.middleNameField = value; + } + } + + /// + public string lastName { + get { + return this.lastNameField; + } + set { + this.lastNameField = value; + } + } + + /// + public string Suffix { + get { + return this.suffixField; + } + set { + this.suffixField = value; + } + } + + /// + public string NameTitle { + get { + return this.nameTitleField; + } + set { + this.nameTitleField = value; + } + } + + /// + public string passportName { + get { + return this.passportNameField; + } + set { + this.passportNameField = value; + } + } + + /// + public string displayName { + get { + return this.displayNameField; + } + set { + this.displayNameField = value; + } + } + + /// + public long puid { + get { + return this.puidField; + } + set { + this.puidField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool puidSpecified { + get { + return this.puidFieldSpecified; + } + set { + this.puidFieldSpecified = value; + } + } + + /// + public long CID { + get { + return this.cIDField; + } + set { + this.cIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool CIDSpecified { + get { + return this.cIDFieldSpecified; + } + set { + this.cIDFieldSpecified = value; + } + } + + /// + public object BrandIdList { + get { + return this.brandIdListField; + } + set { + this.brandIdListField = value; + } + } + + /// + public string comment { + get { + return this.commentField; + } + set { + this.commentField = value; + } + } + + /// + public bool isMobileIMEnabled { + get { + return this.isMobileIMEnabledField; + } + set { + this.isMobileIMEnabledField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool isMobileIMEnabledSpecified { + get { + return this.isMobileIMEnabledFieldSpecified; + } + set { + this.isMobileIMEnabledFieldSpecified = value; + } + } + + /// + public bool isMessengerUser { + get { + return this.isMessengerUserField; + } + set { + this.isMessengerUserField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool isMessengerUserSpecified { + get { + return this.isMessengerUserFieldSpecified; + } + set { + this.isMessengerUserFieldSpecified = value; + } + } + + /// + public bool isFavorite { + get { + return this.isFavoriteField; + } + set { + this.isFavoriteField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool isFavoriteSpecified { + get { + return this.isFavoriteFieldSpecified; + } + set { + this.isFavoriteFieldSpecified = value; + } + } + + /// + public bool isSmtp { + get { + return this.isSmtpField; + } + set { + this.isSmtpField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool isSmtpSpecified { + get { + return this.isSmtpFieldSpecified; + } + set { + this.isSmtpFieldSpecified = value; + } + } + + /// + public bool hasSpace { + get { + return this.hasSpaceField; + } + set { + this.hasSpaceField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool hasSpaceSpecified { + get { + return this.hasSpaceFieldSpecified; + } + set { + this.hasSpaceFieldSpecified = value; + } + } + + /// + public string spotWatchState { + get { + return this.spotWatchStateField; + } + set { + this.spotWatchStateField = value; + } + } + + /// + public string birthdate { + get { + return this.birthdateField; + } + set { + this.birthdateField = value; + } + } + + /// + public ContactEmailTypeType primaryEmailType { + get { + return this.primaryEmailTypeField; + } + set { + this.primaryEmailTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool primaryEmailTypeSpecified { + get { + return this.primaryEmailTypeFieldSpecified; + } + set { + this.primaryEmailTypeFieldSpecified = value; + } + } + + /// + public ContactLocationTypeType PrimaryLocation { + get { + return this.primaryLocationField; + } + set { + this.primaryLocationField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PrimaryLocationSpecified { + get { + return this.primaryLocationFieldSpecified; + } + set { + this.primaryLocationFieldSpecified = value; + } + } + + /// + public string PrimaryPhone { + get { + return this.primaryPhoneField; + } + set { + this.primaryPhoneField = value; + } + } + + /// + public bool IsPrivate { + get { + return this.isPrivateField; + } + set { + this.isPrivateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IsPrivateSpecified { + get { + return this.isPrivateFieldSpecified; + } + set { + this.isPrivateFieldSpecified = value; + } + } + + /// + public string Anniversary { + get { + return this.anniversaryField; + } + set { + this.anniversaryField = value; + } + } + + /// + public string Gender { + get { + return this.genderField; + } + set { + this.genderField = value; + } + } + + /// + public string TimeZone { + get { + return this.timeZoneField; + } + set { + this.timeZoneField = value; + } + } + + /// + public int TrustLevel { + get { + return this.trustLevelField; + } + set { + this.trustLevelField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool TrustLevelSpecified { + get { + return this.trustLevelFieldSpecified; + } + set { + this.trustLevelFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("NetworkInfo", IsNullable=false)] + public NetworkInfoType[] NetworkInfoList { + get { + return this.networkInfoListField; + } + set { + this.networkInfoListField = value; + } + } + + /// + public string PublicDisplayName { + get { + return this.publicDisplayNameField; + } + set { + this.publicDisplayNameField = value; + } + } + + /// + public bool IsAutoUpdateDisabled { + get { + return this.isAutoUpdateDisabledField; + } + set { + this.isAutoUpdateDisabledField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IsAutoUpdateDisabledSpecified { + get { + return this.isAutoUpdateDisabledFieldSpecified; + } + set { + this.isAutoUpdateDisabledFieldSpecified = value; + } + } + + /// + public bool IsHidden { + get { + return this.isHiddenField; + } + set { + this.isHiddenField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IsHiddenSpecified { + get { + return this.isHiddenFieldSpecified; + } + set { + this.isHiddenFieldSpecified = value; + } + } + + /// + public bool IsPassportNameHidden { + get { + return this.isPassportNameHiddenField; + } + set { + this.isPassportNameHiddenField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IsPassportNameHiddenSpecified { + get { + return this.isPassportNameHiddenFieldSpecified; + } + set { + this.isPassportNameHiddenFieldSpecified = value; + } + } + + /// + public bool IsNotMobileVisible { + get { + return this.isNotMobileVisibleField; + } + set { + this.isNotMobileVisibleField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IsNotMobileVisibleSpecified { + get { + return this.isNotMobileVisibleFieldSpecified; + } + set { + this.isNotMobileVisibleFieldSpecified = value; + } + } + + /// + public bool IsShellContact { + get { + return this.isShellContactField; + } + set { + this.isShellContactField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IsShellContactSpecified { + get { + return this.isShellContactFieldSpecified; + } + set { + this.isShellContactFieldSpecified = value; + } + } + + /// + public MessengerMemberInfo MessengerMemberInfo { + get { + return this.messengerMemberInfoField; + } + set { + this.messengerMemberInfoField = value; + } + } + + /// + public object PropertiesChanged { + get { + return this.propertiesChangedField; + } + set { + this.propertiesChangedField = value; + } + } + + /// + public string clientErrorData { + get { + return this.clientErrorDataField; + } + set { + this.clientErrorDataField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class contactEmailType { + + private ContactEmailTypeType contactEmailType1Field; + + private string emailField; + + private bool isMessengerEnabledField; + + private string capabilityField; + + private bool messengerEnabledExternallyField; + + private string propertiesChangedField; + + /// + [System.Xml.Serialization.XmlElementAttribute("contactEmailType")] + public ContactEmailTypeType contactEmailType1 { + get { + return this.contactEmailType1Field; + } + set { + this.contactEmailType1Field = value; + } + } + + /// + public string email { + get { + return this.emailField; + } + set { + this.emailField = value; + } + } + + /// + public bool isMessengerEnabled { + get { + return this.isMessengerEnabledField; + } + set { + this.isMessengerEnabledField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string Capability { + get { + return this.capabilityField; + } + set { + this.capabilityField = value; + } + } + + /// + public bool MessengerEnabledExternally { + get { + return this.messengerEnabledExternallyField; + } + set { + this.messengerEnabledExternallyField = value; + } + } + + /// + public string propertiesChanged { + get { + return this.propertiesChangedField; + } + set { + this.propertiesChangedField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public enum ContactEmailTypeType { + + /// + ContactEmailPersonal, + + /// + ContactEmailBusiness, + + /// + ContactEmailOther, + + /// + ContactEmailMessenger, + + /// + Messenger2, + + /// + Messenger3, + + /// + Messenger4, + + /// + Passport, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class contactPhoneType { + + private string contactPhoneType1Field; + + private string numberField; + + private bool isMessengerEnabledField; + + private string propertiesChangedField; + + /// + [System.Xml.Serialization.XmlElementAttribute("contactPhoneType")] + public string contactPhoneType1 { + get { + return this.contactPhoneType1Field; + } + set { + this.contactPhoneType1Field = value; + } + } + + /// + public string number { + get { + return this.numberField; + } + set { + this.numberField = value; + } + } + + /// + public bool isMessengerEnabled { + get { + return this.isMessengerEnabledField; + } + set { + this.isMessengerEnabledField = value; + } + } + + /// + public string propertiesChanged { + get { + return this.propertiesChangedField; + } + set { + this.propertiesChangedField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class contactLocationType { + + private ContactLocationTypeType contactLocationType1Field; + + private string nameField; + + private string streetField; + + private string cityField; + + private string stateField; + + private string countryField; + + private string postalCodeField; + + private string departmentField; + + private string changesField; + + /// + [System.Xml.Serialization.XmlElementAttribute("contactLocationType")] + public ContactLocationTypeType contactLocationType1 { + get { + return this.contactLocationType1Field; + } + set { + this.contactLocationType1Field = value; + } + } + + /// + public string name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + public string street { + get { + return this.streetField; + } + set { + this.streetField = value; + } + } + + /// + public string city { + get { + return this.cityField; + } + set { + this.cityField = value; + } + } + + /// + public string state { + get { + return this.stateField; + } + set { + this.stateField = value; + } + } + + /// + public string country { + get { + return this.countryField; + } + set { + this.countryField = value; + } + } + + /// + public string postalCode { + get { + return this.postalCodeField; + } + set { + this.postalCodeField = value; + } + } + + /// + public string Department { + get { + return this.departmentField; + } + set { + this.departmentField = value; + } + } + + /// + public string Changes { + get { + return this.changesField; + } + set { + this.changesField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public enum ContactLocationTypeType { + + /// + ContactLocationPersonal, + + /// + ContactLocationBusiness, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class contactWebSiteType { + + private ContactWebSiteTypeType contactWebSiteType1Field; + + private string webURLField; + + /// + [System.Xml.Serialization.XmlElementAttribute("contactWebSiteType")] + public ContactWebSiteTypeType contactWebSiteType1 { + get { + return this.contactWebSiteType1Field; + } + set { + this.contactWebSiteType1Field = value; + } + } + + /// + public string webURL { + get { + return this.webURLField; + } + set { + this.webURLField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public enum ContactWebSiteTypeType { + + /// + ContactWebSitePersonal, + + /// + ContactWebSiteBusiness, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class NetworkInfoType { + + private int domainIdField; + + private bool domainIdFieldSpecified; + + private string domainTagField; + + private string displayNameField; + + private string userTileURLField; + + private string profileURLField; + + private int relationshipTypeField; + + private bool relationshipTypeFieldSpecified; + + private int relationshipStateField; + + private bool relationshipStateFieldSpecified; + + private string relationshipStateDateField; + + private int relationshipRoleField; + + private bool relationshipRoleFieldSpecified; + + private int nDRCountField; + + private bool nDRCountFieldSpecified; + + private string inviterNameField; + + private string inviterMessageField; + + private long inviterCIDField; + + private bool inviterCIDFieldSpecified; + + private string inviterEmailField; + + private string createDateField; + + private string lastChangedField; + + private object propertiesChangedField; + + private string sourceIdField; + + /// + public int DomainId { + get { + return this.domainIdField; + } + set { + this.domainIdField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool DomainIdSpecified { + get { + return this.domainIdFieldSpecified; + } + set { + this.domainIdFieldSpecified = value; + } + } + + /// + public string DomainTag { + get { + return this.domainTagField; + } + set { + this.domainTagField = value; + } + } + + /// + public string DisplayName { + get { + return this.displayNameField; + } + set { + this.displayNameField = value; + } + } + + /// + public string UserTileURL { + get { + return this.userTileURLField; + } + set { + this.userTileURLField = value; + } + } + + /// + public string ProfileURL { + get { + return this.profileURLField; + } + set { + this.profileURLField = value; + } + } + + /// + public int RelationshipType { + get { + return this.relationshipTypeField; + } + set { + this.relationshipTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RelationshipTypeSpecified { + get { + return this.relationshipTypeFieldSpecified; + } + set { + this.relationshipTypeFieldSpecified = value; + } + } + + /// + public int RelationshipState { + get { + return this.relationshipStateField; + } + set { + this.relationshipStateField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RelationshipStateSpecified { + get { + return this.relationshipStateFieldSpecified; + } + set { + this.relationshipStateFieldSpecified = value; + } + } + + /// + public string RelationshipStateDate { + get { + return this.relationshipStateDateField; + } + set { + this.relationshipStateDateField = value; + } + } + + /// + public int RelationshipRole { + get { + return this.relationshipRoleField; + } + set { + this.relationshipRoleField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RelationshipRoleSpecified { + get { + return this.relationshipRoleFieldSpecified; + } + set { + this.relationshipRoleFieldSpecified = value; + } + } + + /// + public int NDRCount { + get { + return this.nDRCountField; + } + set { + this.nDRCountField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool NDRCountSpecified { + get { + return this.nDRCountFieldSpecified; + } + set { + this.nDRCountFieldSpecified = value; + } + } + + /// + public string InviterName { + get { + return this.inviterNameField; + } + set { + this.inviterNameField = value; + } + } + + /// + public string InviterMessage { + get { + return this.inviterMessageField; + } + set { + this.inviterMessageField = value; + } + } + + /// + public long InviterCID { + get { + return this.inviterCIDField; + } + set { + this.inviterCIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool InviterCIDSpecified { + get { + return this.inviterCIDFieldSpecified; + } + set { + this.inviterCIDFieldSpecified = value; + } + } + + /// + public string InviterEmail { + get { + return this.inviterEmailField; + } + set { + this.inviterEmailField = value; + } + } + + /// + public string CreateDate { + get { + return this.createDateField; + } + set { + this.createDateField = value; + } + } + + /// + public string LastChanged { + get { + return this.lastChangedField; + } + set { + this.lastChangedField = value; + } + } + + /// + public object PropertiesChanged { + get { + return this.propertiesChangedField; + } + set { + this.propertiesChangedField = value; + } + } + + /// + public string SourceId { + get { + return this.sourceIdField; + } + set { + this.sourceIdField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class MessengerMemberInfo { + + private Annotation[] pendingAnnotationsField; + + private string displayNameField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)] + public Annotation[] PendingAnnotations { + get { + return this.pendingAnnotationsField; + } + set { + this.pendingAnnotationsField = value; + } + } + + /// + public string DisplayName { + get { + return this.displayNameField; + } + set { + this.displayNameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class CircleResultType { + + private CircleInverseInfoType[] circlesField; + + private string circleTicketField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("CircleInverseInfo", IsNullable=false)] + public CircleInverseInfoType[] Circles { + get { + return this.circlesField; + } + set { + this.circlesField = value; + } + } + + /// + public string CircleTicket { + get { + return this.circleTicketField; + } + set { + this.circleTicketField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class CircleInverseInfoType { + + private ContentType contentField; + + private PersonalInfoType personalInfoField; + + private bool deletedField; + + /// + public ContentType Content { + get { + return this.contentField; + } + set { + this.contentField = value; + } + } + + /// + public PersonalInfoType PersonalInfo { + get { + return this.personalInfoField; + } + set { + this.personalInfoField = value; + } + } + + /// + public bool Deleted { + get { + return this.deletedField; + } + set { + this.deletedField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ContentType { + + private ContentHandleType handleField; + + private ContentInfoType infoField; + + /// + public ContentHandleType Handle { + get { + return this.handleField; + } + set { + this.handleField = value; + } + } + + /// + public ContentInfoType Info { + get { + return this.infoField; + } + set { + this.infoField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ContentHandleType { + + private string idField; + + /// + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ContentInfoType { + + private int domainField; + + private string hostedDomainField; + + private int typeField; + + private int membershipAccessField; + + private bool isPresenceEnabledField; + + private int requestMembershipOptionField; + + private string displayNameField; + + private string profileLastUpdatedField; + + private object changesField; + + private string createDateField; + + private string lastChangedField; + + /// + public int Domain { + get { + return this.domainField; + } + set { + this.domainField = value; + } + } + + /// + public string HostedDomain { + get { + return this.hostedDomainField; + } + set { + this.hostedDomainField = value; + } + } + + /// + public int Type { + get { + return this.typeField; + } + set { + this.typeField = value; + } + } + + /// + public int MembershipAccess { + get { + return this.membershipAccessField; + } + set { + this.membershipAccessField = value; + } + } + + /// + public bool IsPresenceEnabled { + get { + return this.isPresenceEnabledField; + } + set { + this.isPresenceEnabledField = value; + } + } + + /// + public int RequestMembershipOption { + get { + return this.requestMembershipOptionField; + } + set { + this.requestMembershipOptionField = value; + } + } + + /// + public string DisplayName { + get { + return this.displayNameField; + } + set { + this.displayNameField = value; + } + } + + /// + public string ProfileLastUpdated { + get { + return this.profileLastUpdatedField; + } + set { + this.profileLastUpdatedField = value; + } + } + + /// + public object Changes { + get { + return this.changesField; + } + set { + this.changesField = value; + } + } + + /// + public string CreateDate { + get { + return this.createDateField; + } + set { + this.createDateField = value; + } + } + + /// + public string LastChanged { + get { + return this.lastChangedField; + } + set { + this.lastChangedField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class PersonalInfoType { + + private MembershipInfoType membershipInfoField; + + private string nameField; + + private bool isNotMobileVisibleField; + + private bool isFavoriteField; + + private bool isFamilyField; + + private object changesField; + + /// + public MembershipInfoType MembershipInfo { + get { + return this.membershipInfoField; + } + set { + this.membershipInfoField = value; + } + } + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + public bool IsNotMobileVisible { + get { + return this.isNotMobileVisibleField; + } + set { + this.isNotMobileVisibleField = value; + } + } + + /// + public bool IsFavorite { + get { + return this.isFavoriteField; + } + set { + this.isFavoriteField = value; + } + } + + /// + public bool IsFamily { + get { + return this.isFamilyField; + } + set { + this.isFamilyField = value; + } + } + + /// + public object Changes { + get { + return this.changesField; + } + set { + this.changesField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class MembershipInfoType { + + private CirclePersonalMembershipType circlePersonalMembershipField; + + /// + public CirclePersonalMembershipType CirclePersonalMembership { + get { + return this.circlePersonalMembershipField; + } + set { + this.circlePersonalMembershipField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class CirclePersonalMembershipType { + + private string roleField; + + private string stateField; + + /// + public string Role { + get { + return this.roleField; + } + set { + this.roleField = value; + } + } + + /// + public string State { + get { + return this.stateField; + } + set { + this.stateField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABFindContactsPagedResultTypeAB { + + private string abIdField; + + private abInfoType abInfoField; + + private string lastChangeField; + + private string dynamicItemLastChangedField; + + private string recentActivityItemLastChangedField; + + private string createDateField; + + private string propertiesChangedField; + + /// + public string abId { + get { + return this.abIdField; + } + set { + this.abIdField = value; + } + } + + /// + public abInfoType abInfo { + get { + return this.abInfoField; + } + set { + this.abInfoField = value; + } + } + + /// + public string lastChange { + get { + return this.lastChangeField; + } + set { + this.lastChangeField = value; + } + } + + /// + public string DynamicItemLastChanged { + get { + return this.dynamicItemLastChangedField; + } + set { + this.dynamicItemLastChangedField = value; + } + } + + /// + public string RecentActivityItemLastChanged { + get { + return this.recentActivityItemLastChangedField; + } + set { + this.recentActivityItemLastChangedField = value; + } + } + + /// + public string createDate { + get { + return this.createDateField; + } + set { + this.createDateField = value; + } + } + + /// + public string propertiesChanged { + get { + return this.propertiesChangedField; + } + set { + this.propertiesChangedField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class abInfoType { + + private string nameField; + + private string ownerPuidField; + + private string ownerCIDField; + + private string ownerEmailField; + + private bool fDefaultField; + + private bool joinedNamespaceField; + + private bool joinedNamespaceFieldSpecified; + + private bool isBotField; + + private bool isBotFieldSpecified; + + private bool isParentManagedField; + + private bool isParentManagedFieldSpecified; + + private bool subscribeExternalPartnerField; + + private bool subscribeExternalPartnerFieldSpecified; + + private bool notifyExternalPartnerField; + + private bool notifyExternalPartnerFieldSpecified; + + private string addressBookTypeField; + + private bool messengerApplicationServiceCreatedField; + + private bool messengerApplicationServiceCreatedFieldSpecified; + + private bool isBetaMigratedField; + + private bool isBetaMigratedFieldSpecified; + + private int migratedToField; + + private bool migratedToFieldSpecified; + + /// + public string name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + public string ownerPuid { + get { + return this.ownerPuidField; + } + set { + this.ownerPuidField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string OwnerCID { + get { + return this.ownerCIDField; + } + set { + this.ownerCIDField = value; + } + } + + /// + public string ownerEmail { + get { + return this.ownerEmailField; + } + set { + this.ownerEmailField = value; + } + } + + /// + public bool fDefault { + get { + return this.fDefaultField; + } + set { + this.fDefaultField = value; + } + } + + /// + public bool joinedNamespace { + get { + return this.joinedNamespaceField; + } + set { + this.joinedNamespaceField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool joinedNamespaceSpecified { + get { + return this.joinedNamespaceFieldSpecified; + } + set { + this.joinedNamespaceFieldSpecified = value; + } + } + + /// + public bool IsBot { + get { + return this.isBotField; + } + set { + this.isBotField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IsBotSpecified { + get { + return this.isBotFieldSpecified; + } + set { + this.isBotFieldSpecified = value; + } + } + + /// + public bool IsParentManaged { + get { + return this.isParentManagedField; + } + set { + this.isParentManagedField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IsParentManagedSpecified { + get { + return this.isParentManagedFieldSpecified; + } + set { + this.isParentManagedFieldSpecified = value; + } + } + + /// + public bool SubscribeExternalPartner { + get { + return this.subscribeExternalPartnerField; + } + set { + this.subscribeExternalPartnerField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool SubscribeExternalPartnerSpecified { + get { + return this.subscribeExternalPartnerFieldSpecified; + } + set { + this.subscribeExternalPartnerFieldSpecified = value; + } + } + + /// + public bool NotifyExternalPartner { + get { + return this.notifyExternalPartnerField; + } + set { + this.notifyExternalPartnerField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool NotifyExternalPartnerSpecified { + get { + return this.notifyExternalPartnerFieldSpecified; + } + set { + this.notifyExternalPartnerFieldSpecified = value; + } + } + + /// + public string AddressBookType { + get { + return this.addressBookTypeField; + } + set { + this.addressBookTypeField = value; + } + } + + /// + public bool MessengerApplicationServiceCreated { + get { + return this.messengerApplicationServiceCreatedField; + } + set { + this.messengerApplicationServiceCreatedField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool MessengerApplicationServiceCreatedSpecified { + get { + return this.messengerApplicationServiceCreatedFieldSpecified; + } + set { + this.messengerApplicationServiceCreatedFieldSpecified = value; + } + } + + /// + public bool IsBetaMigrated { + get { + return this.isBetaMigratedField; + } + set { + this.isBetaMigratedField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IsBetaMigratedSpecified { + get { + return this.isBetaMigratedFieldSpecified; + } + set { + this.isBetaMigratedFieldSpecified = value; + } + } + + /// + public int MigratedTo { + get { + return this.migratedToField; + } + set { + this.migratedToField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool MigratedToSpecified { + get { + return this.migratedToFieldSpecified; + } + set { + this.migratedToFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABFindContactsPagedRequestType { + + private filterOptionsType filterOptionsField; + + private string abViewField; + + private string extendedContentField; + + private abHandleType abHandleField; + + private pageContextType pageContextField; + + /// + public filterOptionsType filterOptions { + get { + return this.filterOptionsField; + } + set { + this.filterOptionsField = value; + } + } + + /// + public string abView { + get { + return this.abViewField; + } + set { + this.abViewField = value; + } + } + + /// + public string extendedContent { + get { + return this.extendedContentField; + } + set { + this.extendedContentField = value; + } + } + + /// + public abHandleType abHandle { + get { + return this.abHandleField; + } + set { + this.abHandleField = value; + } + } + + /// + public pageContextType pageContext { + get { + return this.pageContextField; + } + set { + this.pageContextField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class filterOptionsType { + + private bool deltasOnlyField; + + private string lastChangedField; + + private ContactFilterType contactFilterField; + + /// + public bool DeltasOnly { + get { + return this.deltasOnlyField; + } + set { + this.deltasOnlyField = value; + } + } + + /// + public string LastChanged { + get { + return this.lastChangedField; + } + set { + this.lastChangedField = value; + } + } + + /// + public ContactFilterType ContactFilter { + get { + return this.contactFilterField; + } + set { + this.contactFilterField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ContactFilterType { + + private bool includeHiddenContactsField; + + private bool includeShellContactsField; + + private bool includeShellContactsFieldSpecified; + + /// + public bool IncludeHiddenContacts { + get { + return this.includeHiddenContactsField; + } + set { + this.includeHiddenContactsField = value; + } + } + + /// + public bool IncludeShellContacts { + get { + return this.includeShellContactsField; + } + set { + this.includeShellContactsField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IncludeShellContactsSpecified { + get { + return this.includeShellContactsFieldSpecified; + } + set { + this.includeShellContactsFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class pageContextType { + + private int pageSizeField; + + private string directionField; + + /// + public int PageSize { + get { + return this.pageSizeField; + } + set { + this.pageSizeField = value; + } + } + + /// + public string Direction { + get { + return this.directionField; + } + set { + this.directionField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class UpdateDynamicItemRequestType { + + private string abIdField; + + private BaseDynamicItemType[] dynamicItemsField; + + /// + public string abId { + get { + return this.abIdField; + } + set { + this.abIdField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("DynamicItem", IsNullable=false)] + public BaseDynamicItemType[] dynamicItems { + get { + return this.dynamicItemsField; + } + set { + this.dynamicItemsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABAddRequestType { + + private abInfoType abInfoField; + + /// + public abInfoType abInfo { + get { + return this.abInfoField; + } + set { + this.abInfoField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABAddResponseType { + + private string aBAddResultField; + + /// + public string ABAddResult { + get { + return this.aBAddResultField; + } + set { + this.aBAddResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABGroupContactDeleteRequestType { + + private string abIdField; + + private ContactType[] contactsField; + + private groupFilterType groupFilterField; + + public ABGroupContactDeleteRequestType() { + this.abIdField = "00000000-0000-0000-0000-000000000000"; + } + + /// + public string abId { + get { + return this.abIdField; + } + set { + this.abIdField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Contact", IsNullable=false)] + public ContactType[] contacts { + get { + return this.contactsField; + } + set { + this.contactsField = value; + } + } + + /// + public groupFilterType groupFilter { + get { + return this.groupFilterField; + } + set { + this.groupFilterField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class groupFilterType { + + private string[] groupIdsField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("guid", IsNullable=false)] + public string[] groupIds { + get { + return this.groupIdsField; + } + set { + this.groupIdsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABContactUpdateRequestType { + + private string abIdField; + + private ContactType[] contactsField; + + private ABContactUpdateRequestTypeOptions optionsField; + + public ABContactUpdateRequestType() { + this.abIdField = "00000000-0000-0000-0000-000000000000"; + } + + /// + public string abId { + get { + return this.abIdField; + } + set { + this.abIdField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Contact", IsNullable=false)] + public ContactType[] contacts { + get { + return this.contactsField; + } + set { + this.contactsField = value; + } + } + + /// + public ABContactUpdateRequestTypeOptions options { + get { + return this.optionsField; + } + set { + this.optionsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABContactUpdateRequestTypeOptions { + + private bool enableAllowListManagementField; + + private bool enableAllowListManagementFieldSpecified; + + /// + public bool EnableAllowListManagement { + get { + return this.enableAllowListManagementField; + } + set { + this.enableAllowListManagementField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool EnableAllowListManagementSpecified { + get { + return this.enableAllowListManagementFieldSpecified; + } + set { + this.enableAllowListManagementFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABGroupDeleteRequestType { + + private string abIdField; + + private groupFilterType groupFilterField; + + public ABGroupDeleteRequestType() { + this.abIdField = "00000000-0000-0000-0000-000000000000"; + } + + /// + public string abId { + get { + return this.abIdField; + } + set { + this.abIdField = value; + } + } + + /// + public groupFilterType groupFilter { + get { + return this.groupFilterField; + } + set { + this.groupFilterField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABGroupUpdateRequestType { + + private string abIdField; + + private GroupType[] groupsField; + + public ABGroupUpdateRequestType() { + this.abIdField = "00000000-0000-0000-0000-000000000000"; + } + + /// + public string abId { + get { + return this.abIdField; + } + set { + this.abIdField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Group", IsNullable=false)] + public GroupType[] groups { + get { + return this.groupsField; + } + set { + this.groupsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABGroupAddResultType { + + private string guidField; + + /// + public string guid { + get { + return this.guidField; + } + set { + this.guidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABGroupAddRequestType { + + private string abIdField; + + private ABGroupAddRequestTypeGroupAddOptions groupAddOptionsField; + + private ABGroupAddRequestTypeGroupInfo groupInfoField; + + public ABGroupAddRequestType() { + this.abIdField = "00000000-0000-0000-0000-000000000000"; + } + + /// + public string abId { + get { + return this.abIdField; + } + set { + this.abIdField = value; + } + } + + /// + public ABGroupAddRequestTypeGroupAddOptions groupAddOptions { + get { + return this.groupAddOptionsField; + } + set { + this.groupAddOptionsField = value; + } + } + + /// + public ABGroupAddRequestTypeGroupInfo groupInfo { + get { + return this.groupInfoField; + } + set { + this.groupInfoField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABGroupAddRequestTypeGroupAddOptions { + + private bool fRenameOnMsgrConflictField; + + private bool fRenameOnMsgrConflictFieldSpecified; + + /// + public bool fRenameOnMsgrConflict { + get { + return this.fRenameOnMsgrConflictField; + } + set { + this.fRenameOnMsgrConflictField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool fRenameOnMsgrConflictSpecified { + get { + return this.fRenameOnMsgrConflictFieldSpecified; + } + set { + this.fRenameOnMsgrConflictFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABGroupAddRequestTypeGroupInfo { + + private groupInfoType groupInfoField; + + /// + public groupInfoType GroupInfo { + get { + return this.groupInfoField; + } + set { + this.groupInfoField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABGroupContactAddResultType { + + private string guidField; + + /// + public string guid { + get { + return this.guidField; + } + set { + this.guidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABGroupContactAddRequestType { + + private string abIdField; + + private groupFilterType groupFilterField; + + private ContactType[] contactsField; + + private ABGroupContactAddRequestTypeGroupContactAddOptions groupContactAddOptionsField; + + public ABGroupContactAddRequestType() { + this.abIdField = "00000000-0000-0000-0000-000000000000"; + } + + /// + public string abId { + get { + return this.abIdField; + } + set { + this.abIdField = value; + } + } + + /// + public groupFilterType groupFilter { + get { + return this.groupFilterField; + } + set { + this.groupFilterField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Contact", IsNullable=false)] + public ContactType[] contacts { + get { + return this.contactsField; + } + set { + this.contactsField = value; + } + } + + /// + public ABGroupContactAddRequestTypeGroupContactAddOptions groupContactAddOptions { + get { + return this.groupContactAddOptionsField; + } + set { + this.groupContactAddOptionsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABGroupContactAddRequestTypeGroupContactAddOptions { + + private bool fGenerateMissingQuickNameField; + + private bool fGenerateMissingQuickNameFieldSpecified; + + private bool enableAllowListManagementField; + + private bool enableAllowListManagementFieldSpecified; + + /// + public bool fGenerateMissingQuickName { + get { + return this.fGenerateMissingQuickNameField; + } + set { + this.fGenerateMissingQuickNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool fGenerateMissingQuickNameSpecified { + get { + return this.fGenerateMissingQuickNameFieldSpecified; + } + set { + this.fGenerateMissingQuickNameFieldSpecified = value; + } + } + + /// + public bool EnableAllowListManagement { + get { + return this.enableAllowListManagementField; + } + set { + this.enableAllowListManagementField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool EnableAllowListManagementSpecified { + get { + return this.enableAllowListManagementFieldSpecified; + } + set { + this.enableAllowListManagementFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABContactDeleteRequestType { + + private string abIdField; + + private ContactIdType[] contactsField; + + public ABContactDeleteRequestType() { + this.abIdField = "00000000-0000-0000-0000-000000000000"; + } + + /// + public string abId { + get { + return this.abIdField; + } + set { + this.abIdField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Contact", IsNullable=false)] + public ContactIdType[] contacts { + get { + return this.contactsField; + } + set { + this.contactsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ContactIdType { + + private string contactIdField; + + /// + public string contactId { + get { + return this.contactIdField; + } + set { + this.contactIdField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABContactAddResultType { + + private string guidField; + + /// + public string guid { + get { + return this.guidField; + } + set { + this.guidField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABContactAddRequestType { + + private string abIdField; + + private ContactType[] contactsField; + + private ABContactAddRequestTypeOptions optionsField; + + public ABContactAddRequestType() { + this.abIdField = "00000000-0000-0000-0000-000000000000"; + } + + /// + public string abId { + get { + return this.abIdField; + } + set { + this.abIdField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Contact", IsNullable=false)] + public ContactType[] contacts { + get { + return this.contactsField; + } + set { + this.contactsField = value; + } + } + + /// + public ABContactAddRequestTypeOptions options { + get { + return this.optionsField; + } + set { + this.optionsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABContactAddRequestTypeOptions { + + private bool enableAllowListManagementField; + + /// + public bool EnableAllowListManagement { + get { + return this.enableAllowListManagementField; + } + set { + this.enableAllowListManagementField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABFindByContactsResponseType { + + private ContactType[] contactsField; + + private abType abField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Contact", IsNullable=false)] + public ContactType[] contacts { + get { + return this.contactsField; + } + set { + this.contactsField = value; + } + } + + /// + public abType ab { + get { + return this.abField; + } + set { + this.abField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class abType { + + private string abIdField; + + private abInfoType abInfoField; + + private string lastChangeField; + + private string dynamicItemLastChangedField; + + private string recentActivityItemLastChangedField; + + private string createDateField; + + private object propertiesChangedField; + + /// + public string abId { + get { + return this.abIdField; + } + set { + this.abIdField = value; + } + } + + /// + public abInfoType abInfo { + get { + return this.abInfoField; + } + set { + this.abInfoField = value; + } + } + + /// + public string lastChange { + get { + return this.lastChangeField; + } + set { + this.lastChangeField = value; + } + } + + /// + public string DynamicItemLastChanged { + get { + return this.dynamicItemLastChangedField; + } + set { + this.dynamicItemLastChangedField = value; + } + } + + /// + public string RecentActivityItemLastChanged { + get { + return this.recentActivityItemLastChangedField; + } + set { + this.recentActivityItemLastChangedField = value; + } + } + + /// + public string createDate { + get { + return this.createDateField; + } + set { + this.createDateField = value; + } + } + + /// + public object propertiesChanged { + get { + return this.propertiesChangedField; + } + set { + this.propertiesChangedField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABFindByContactsRequestType { + + private string abIdField; + + private string abViewField; + + private string[] contactIdsField; + + /// + public string abId { + get { + return this.abIdField; + } + set { + this.abIdField = value; + } + } + + /// + public string abView { + get { + return this.abViewField; + } + set { + this.abViewField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("guid", IsNullable=false)] + public string[] contactIds { + get { + return this.contactIdsField; + } + set { + this.contactIdsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABFindAllResultType { + + private GroupType[] groupsField; + + private ContactType[] contactsField; + + private BaseDynamicItemType[] dynamicItemsField; + + private ABFindAllResultTypeCircleResult circleResultField; + + private ABFindAllResultTypeAB abField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Group", IsNullable=false)] + public GroupType[] groups { + get { + return this.groupsField; + } + set { + this.groupsField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Contact", IsNullable=false)] + public ContactType[] contacts { + get { + return this.contactsField; + } + set { + this.contactsField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("DynamicItem", IsNullable=false)] + public BaseDynamicItemType[] DynamicItems { + get { + return this.dynamicItemsField; + } + set { + this.dynamicItemsField = value; + } + } + + /// + public ABFindAllResultTypeCircleResult CircleResult { + get { + return this.circleResultField; + } + set { + this.circleResultField = value; + } + } + + /// + public ABFindAllResultTypeAB ab { + get { + return this.abField; + } + set { + this.abField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABFindAllResultTypeCircleResult { + + private string circleTicketField; + + /// + public string CircleTicket { + get { + return this.circleTicketField; + } + set { + this.circleTicketField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABFindAllResultTypeAB { + + private string abIdField; + + private abInfoType abInfoField; + + private string lastChangeField; + + private string dynamicItemLastChangedField; + + private string recentActivityItemLastChangedField; + + private string createDateField; + + private string propertiesChangedField; + + /// + public string abId { + get { + return this.abIdField; + } + set { + this.abIdField = value; + } + } + + /// + public abInfoType abInfo { + get { + return this.abInfoField; + } + set { + this.abInfoField = value; + } + } + + /// + public string lastChange { + get { + return this.lastChangeField; + } + set { + this.lastChangeField = value; + } + } + + /// + public string DynamicItemLastChanged { + get { + return this.dynamicItemLastChangedField; + } + set { + this.dynamicItemLastChangedField = value; + } + } + + /// + public string RecentActivityItemLastChanged { + get { + return this.recentActivityItemLastChangedField; + } + set { + this.recentActivityItemLastChangedField = value; + } + } + + /// + public string createDate { + get { + return this.createDateField; + } + set { + this.createDateField = value; + } + } + + /// + public string propertiesChanged { + get { + return this.propertiesChangedField; + } + set { + this.propertiesChangedField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABFindAllRequestType { + + private string abIdField; + + private string abViewField; + + private bool deltasOnlyField; + + private string lastChangeField; + + private string dynamicItemViewField; + + private string dynamicItemLastChangeField; + + public ABFindAllRequestType() { + this.abIdField = "00000000-0000-0000-0000-000000000000"; + this.deltasOnlyField = false; + this.lastChangeField = "0001-01-01T00:00:00.0000000-08:00"; + this.dynamicItemViewField = "Gleam"; + this.dynamicItemLastChangeField = "0001-01-01T00:00:00.0000000-08:00"; + } + + /// + public string abId { + get { + return this.abIdField; + } + set { + this.abIdField = value; + } + } + + /// + public string abView { + get { + return this.abViewField; + } + set { + this.abViewField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(false)] + public bool deltasOnly { + get { + return this.deltasOnlyField; + } + set { + this.deltasOnlyField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute("0001-01-01T00:00:00.0000000-08:00")] + public string lastChange { + get { + return this.lastChangeField; + } + set { + this.lastChangeField = value; + } + } + + /// + public string dynamicItemView { + get { + return this.dynamicItemViewField; + } + set { + this.dynamicItemViewField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute("0001-01-01T00:00:00.0000000-08:00")] + public string dynamicItemLastChange { + get { + return this.dynamicItemLastChangeField; + } + set { + this.dynamicItemLastChangeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class callerInfoType { + + private string publicDisplayNameField; + + /// + public string PublicDisplayName { + get { + return this.publicDisplayNameField; + } + set { + this.publicDisplayNameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class CreateCircleRequestType { + + private ContentInfoType propertiesField; + + private callerInfoType callerInfoField; + + /// + public ContentInfoType properties { + get { + return this.propertiesField; + } + set { + this.propertiesField = value; + } + } + + /// + public callerInfoType callerInfo { + get { + return this.callerInfoField; + } + set { + this.callerInfoField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class DeleteMemberRequestType { + + private HandleType serviceHandleField; + + private Membership[] membershipsField; + + private ContentHandleType nsHandleField; + + /// + public HandleType serviceHandle { + get { + return this.serviceHandleField; + } + set { + this.serviceHandleField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)] + public Membership[] memberships { + get { + return this.membershipsField; + } + set { + this.membershipsField = value; + } + } + + /// + public ContentHandleType nsHandle { + get { + return this.nsHandleField; + } + set { + this.nsHandleField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class AddMemberRequestType { + + private HandleType serviceHandleField; + + private Membership[] membershipsField; + + /// + public HandleType serviceHandle { + get { + return this.serviceHandleField; + } + set { + this.serviceHandleField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)] + public Membership[] memberships { + get { + return this.membershipsField; + } + set { + this.membershipsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class CircleAttributesType { + + private bool isPresenceEnabledField; + + private bool isEventField; + + private bool isEventFieldSpecified; + + private string domainField; + + /// + public bool IsPresenceEnabled { + get { + return this.isPresenceEnabledField; + } + set { + this.isPresenceEnabledField = value; + } + } + + /// + public bool IsEvent { + get { + return this.isEventField; + } + set { + this.isEventField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IsEventSpecified { + get { + return this.isEventFieldSpecified; + } + set { + this.isEventFieldSpecified = value; + } + } + + /// + public string Domain { + get { + return this.domainField; + } + set { + this.domainField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class OwnerNamespaceInfoType { + + private OwnerNamespaceInfoTypeHandle handleField; + + private string creatorPuidField; + + private string creatorCIDField; + + private string creatorPassportNameField; + + private CircleAttributesType circleAttributesField; + + private bool messengerApplicationServiceCreatedField; + + private bool messengerApplicationServiceCreatedFieldSpecified; + + /// + public OwnerNamespaceInfoTypeHandle Handle { + get { + return this.handleField; + } + set { + this.handleField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string CreatorPuid { + get { + return this.creatorPuidField; + } + set { + this.creatorPuidField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string CreatorCID { + get { + return this.creatorCIDField; + } + set { + this.creatorCIDField = value; + } + } + + /// + public string CreatorPassportName { + get { + return this.creatorPassportNameField; + } + set { + this.creatorPassportNameField = value; + } + } + + /// + public CircleAttributesType CircleAttributes { + get { + return this.circleAttributesField; + } + set { + this.circleAttributesField = value; + } + } + + /// + public bool MessengerApplicationServiceCreated { + get { + return this.messengerApplicationServiceCreatedField; + } + set { + this.messengerApplicationServiceCreatedField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool MessengerApplicationServiceCreatedSpecified { + get { + return this.messengerApplicationServiceCreatedFieldSpecified; + } + set { + this.messengerApplicationServiceCreatedFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class OwnerNamespaceInfoTypeHandle { + + private string idField; + + private bool isPassportNameHiddenField; + + private string cIDField; + + /// + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + public bool IsPassportNameHidden { + get { + return this.isPassportNameHiddenField; + } + set { + this.isPassportNameHiddenField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string CID { + get { + return this.cIDField; + } + set { + this.cIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class OwnerNamespaceType { + + private OwnerNamespaceInfoType infoField; + + private string changesField; + + private string createDateField; + + private string lastChangeField; + + /// + public OwnerNamespaceInfoType Info { + get { + return this.infoField; + } + set { + this.infoField = value; + } + } + + /// + public string Changes { + get { + return this.changesField; + } + set { + this.changesField = value; + } + } + + /// + public string CreateDate { + get { + return this.createDateField; + } + set { + this.createDateField = value; + } + } + + /// + public string LastChange { + get { + return this.lastChangeField; + } + set { + this.lastChangeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class FindMembershipResultType { + + private ServiceType[] servicesField; + + private OwnerNamespaceType ownerNamespaceField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Service", IsNullable=false)] + public ServiceType[] Services { + get { + return this.servicesField; + } + set { + this.servicesField = value; + } + } + + /// + public OwnerNamespaceType OwnerNamespace { + get { + return this.ownerNamespaceField; + } + set { + this.ownerNamespaceField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class FindMembershipRequestType { + + private FindMembershipRequestTypeServiceFilter serviceFilterField; + + private string viewField; + + private bool deltasOnlyField; + + private string lastChangeField; + + public FindMembershipRequestType() { + this.deltasOnlyField = false; + this.lastChangeField = "0001-01-01T00:00:00.0000000-08:00"; + } + + /// + public FindMembershipRequestTypeServiceFilter serviceFilter { + get { + return this.serviceFilterField; + } + set { + this.serviceFilterField = value; + } + } + + /// + public string View { + get { + return this.viewField; + } + set { + this.viewField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(false)] + public bool deltasOnly { + get { + return this.deltasOnlyField; + } + set { + this.deltasOnlyField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute("0001-01-01T00:00:00.0000000-08:00")] + public string lastChange { + get { + return this.lastChangeField; + } + set { + this.lastChangeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class FindMembershipRequestTypeServiceFilter { + + private string[] typesField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("ServiceType", IsNullable=false)] + public string[] Types { + get { + return this.typesField; + } + set { + this.typesField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.msn.com/webservices/AddressBook", IsNullable=false)] + public partial class WNAuthHeader : System.Web.Services.Protocols.SoapHeader { + + private string ticketTokenField; + + /// + public string TicketToken { + get { + return this.ticketTokenField; + } + set { + this.ticketTokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.msn.com/webservices/AddressBook", IsNullable=false)] + public partial class WNApplicationHeader : System.Web.Services.Protocols.SoapHeader { + + private string applicationIdField; + + /// + public string ApplicationId { + get { + return this.applicationIdField; + } + set { + this.applicationIdField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.msn.com/webservices/AddressBook", IsNullable=false)] + public partial class WNServiceHeader : System.Web.Services.Protocols.SoapHeader { + + private string versionField; + + private string cacheKeyField; + + private bool cacheKeyChangedField; + + private bool cacheKeyChangedFieldSpecified; + + private string preferredHostNameField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="token")] + public string Version { + get { + return this.versionField; + } + set { + this.versionField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="token")] + public string CacheKey { + get { + return this.cacheKeyField; + } + set { + this.cacheKeyField = value; + } + } + + /// + public bool CacheKeyChanged { + get { + return this.cacheKeyChangedField; + } + set { + this.cacheKeyChangedField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool CacheKeyChangedSpecified { + get { + return this.cacheKeyChangedFieldSpecified; + } + set { + this.cacheKeyChangedFieldSpecified = value; + } + } + + /// + public string PreferredHostName { + get { + return this.preferredHostNameField; + } + set { + this.preferredHostNameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.msn.com/webservices/AddressBook", IsNullable=false)] + public partial class ServiceHeader : System.Web.Services.Protocols.SoapHeader { + + private string versionField; + + private string cacheKeyField; + + private bool cacheKeyChangedField; + + private bool cacheKeyChangedFieldSpecified; + + private string preferredHostNameField; + + private string sessionIdField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="token")] + public string Version { + get { + return this.versionField; + } + set { + this.versionField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="token")] + public string CacheKey { + get { + return this.cacheKeyField; + } + set { + this.cacheKeyField = value; + } + } + + /// + public bool CacheKeyChanged { + get { + return this.cacheKeyChangedField; + } + set { + this.cacheKeyChangedField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool CacheKeyChangedSpecified { + get { + return this.cacheKeyChangedFieldSpecified; + } + set { + this.cacheKeyChangedFieldSpecified = value; + } + } + + /// + public string PreferredHostName { + get { + return this.preferredHostNameField; + } + set { + this.preferredHostNameField = value; + } + } + + /// + public string SessionId { + get { + return this.sessionIdField; + } + set { + this.sessionIdField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.msn.com/webservices/AddressBook", IsNullable=false)] + public partial class ABApplicationHeader : System.Web.Services.Protocols.SoapHeader { + + private string applicationIdField; + + private bool isMigrationField; + + private string partnerScenarioField; + + private string cacheKeyField; + + private string brandIdField; + + public ABApplicationHeader() { + this.applicationIdField = "09607671-1C32-421F-A6A6-CBFAA51AB5F4"; + this.isMigrationField = false; + this.partnerScenarioField = "Initial"; + } + + /// + public string ApplicationId { + get { + return this.applicationIdField; + } + set { + this.applicationIdField = value; + } + } + + /// + public bool IsMigration { + get { + return this.isMigrationField; + } + set { + this.isMigrationField = value; + } + } + + /// + public string PartnerScenario { + get { + return this.partnerScenarioField; + } + set { + this.partnerScenarioField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="token")] + public string CacheKey { + get { + return this.cacheKeyField; + } + set { + this.cacheKeyField = value; + } + } + + /// + public string BrandId { + get { + return this.brandIdField; + } + set { + this.brandIdField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class FindMembershipResponse { + + private FindMembershipResultType findMembershipResultField; + + /// + public FindMembershipResultType FindMembershipResult { + get { + return this.findMembershipResultField; + } + set { + this.findMembershipResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class AddMemberResponse { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class DeleteMemberResponse { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class CreateCircleResponse { + + private CreateCircleResponseType createCircleResultField; + + /// + public CreateCircleResponseType CreateCircleResult { + get { + return this.createCircleResultField; + } + set { + this.createCircleResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABFindAllResponse { + + private ABFindAllResultType aBFindAllResultField; + + /// + public ABFindAllResultType ABFindAllResult { + get { + return this.aBFindAllResultField; + } + set { + this.aBFindAllResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABContactAddResponse { + + private ABContactAddResultType aBContactAddResultField; + + /// + public ABContactAddResultType ABContactAddResult { + get { + return this.aBContactAddResultField; + } + set { + this.aBContactAddResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABGroupContactAddResponse { + + private ABGroupContactAddResultType aBGroupContactAddResultField; + + /// + public ABGroupContactAddResultType ABGroupContactAddResult { + get { + return this.aBGroupContactAddResultField; + } + set { + this.aBGroupContactAddResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABGroupAddResponse { + + private ABGroupAddResultType aBGroupAddResultField; + + /// + public ABGroupAddResultType ABGroupAddResult { + get { + return this.aBGroupAddResultField; + } + set { + this.aBGroupAddResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABGroupUpdateResponse { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABGroupDeleteResponse { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABGroupContactDeleteResponse { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABContactUpdateResponse { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABFindContactsPagedResponse { + + private ABFindContactsPagedResultType aBFindContactsPagedResultField; + + /// + public ABFindContactsPagedResultType ABFindContactsPagedResult { + get { + return this.aBFindContactsPagedResultField; + } + set { + this.aBFindContactsPagedResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class CreateContactResponse { + + private ContactType createContactResultField; + + /// + public ContactType CreateContactResult { + get { + return this.createContactResultField; + } + set { + this.createContactResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ManageWLConnectionResponse { + + private ContactType manageWLConnectionResultField; + + /// + public ContactType ManageWLConnectionResult { + get { + return this.manageWLConnectionResultField; + } + set { + this.manageWLConnectionResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class ABFindByContactsResponse { + + private ABFindByContactsResponseType aBFindByContactsResultField; + + /// + public ABFindByContactsResponseType ABFindByContactsResult { + get { + return this.aBFindByContactsResultField; + } + set { + this.aBFindByContactsResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/AddressBook")] + public partial class GetContactsRecentActivityResponse { + + private GetContactsRecentActivityResultType getContactsRecentActivityResultField; + + /// + public GetContactsRecentActivityResultType GetContactsRecentActivityResult { + get { + return this.getContactsRecentActivityResultField; + } + set { + this.getContactsRecentActivityResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void FindMembershipCompletedEventHandler(object sender, FindMembershipCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class FindMembershipCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal FindMembershipCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public FindMembershipResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((FindMembershipResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void AddMemberCompletedEventHandler(object sender, AddMemberCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class AddMemberCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal AddMemberCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public AddMemberResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((AddMemberResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void DeleteMemberCompletedEventHandler(object sender, DeleteMemberCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class DeleteMemberCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal DeleteMemberCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public DeleteMemberResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((DeleteMemberResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void CreateCircleCompletedEventHandler(object sender, CreateCircleCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class CreateCircleCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal CreateCircleCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public CreateCircleResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((CreateCircleResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void ABFindAllCompletedEventHandler(object sender, ABFindAllCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ABFindAllCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ABFindAllCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ABFindAllResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ABFindAllResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void ABContactAddCompletedEventHandler(object sender, ABContactAddCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ABContactAddCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ABContactAddCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ABContactAddResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ABContactAddResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void ABContactDeleteCompletedEventHandler(object sender, ABContactDeleteCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ABContactDeleteCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ABContactDeleteCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public object Result { + get { + this.RaiseExceptionIfNecessary(); + return ((object)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void ABGroupContactAddCompletedEventHandler(object sender, ABGroupContactAddCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ABGroupContactAddCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ABGroupContactAddCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ABGroupContactAddResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ABGroupContactAddResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void ABGroupAddCompletedEventHandler(object sender, ABGroupAddCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ABGroupAddCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ABGroupAddCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ABGroupAddResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ABGroupAddResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void ABGroupUpdateCompletedEventHandler(object sender, ABGroupUpdateCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ABGroupUpdateCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ABGroupUpdateCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ABGroupUpdateResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ABGroupUpdateResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void ABGroupDeleteCompletedEventHandler(object sender, ABGroupDeleteCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ABGroupDeleteCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ABGroupDeleteCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ABGroupDeleteResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ABGroupDeleteResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void ABGroupContactDeleteCompletedEventHandler(object sender, ABGroupContactDeleteCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ABGroupContactDeleteCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ABGroupContactDeleteCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ABGroupContactDeleteResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ABGroupContactDeleteResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void ABContactUpdateCompletedEventHandler(object sender, ABContactUpdateCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ABContactUpdateCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ABContactUpdateCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ABContactUpdateResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ABContactUpdateResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void ABAddCompletedEventHandler(object sender, ABAddCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ABAddCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ABAddCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ABAddResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ABAddResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void UpdateDynamicItemCompletedEventHandler(object sender, UpdateDynamicItemCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class UpdateDynamicItemCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal UpdateDynamicItemCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public object Result { + get { + this.RaiseExceptionIfNecessary(); + return ((object)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void ABFindContactsPagedCompletedEventHandler(object sender, ABFindContactsPagedCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ABFindContactsPagedCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ABFindContactsPagedCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ABFindContactsPagedResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ABFindContactsPagedResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void CreateContactCompletedEventHandler(object sender, CreateContactCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class CreateContactCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal CreateContactCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public CreateContactResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((CreateContactResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void ManageWLConnectionCompletedEventHandler(object sender, ManageWLConnectionCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ManageWLConnectionCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ManageWLConnectionCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ManageWLConnectionResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ManageWLConnectionResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void BreakConnectionCompletedEventHandler(object sender, BreakConnectionCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class BreakConnectionCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal BreakConnectionCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public BreakConnectionResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((BreakConnectionResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void AddDynamicItemCompletedEventHandler(object sender, AddDynamicItemCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class AddDynamicItemCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal AddDynamicItemCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public AddDynamicItemResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((AddDynamicItemResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void ABFindByContactsCompletedEventHandler(object sender, ABFindByContactsCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ABFindByContactsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ABFindByContactsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ABFindByContactsResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ABFindByContactsResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void GetContactsRecentActivityCompletedEventHandler(object sender, GetContactsRecentActivityCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class GetContactsRecentActivityCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal GetContactsRecentActivityCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public GetContactsRecentActivityResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((GetContactsRecentActivityResponse)(this.results[0])); + } + } + } +} + +#pragma warning restore 1591 \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/Reference.map b/MSNPSharp/Web References/MSNWS.MSNABSharingService/Reference.map new file mode 100644 index 0000000..3988acd --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/Reference.map @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/msnab_datatypes.xsd b/MSNPSharp/Web References/MSNWS.MSNABSharingService/msnab_datatypes.xsd new file mode 100644 index 0000000..94733bc --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/msnab_datatypes.xsd @@ -0,0 +1,925 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A space (ASCII #32) separated list of properties that + have changed as part of an update request. The property + names don't always match the name of the associated + element. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Indicates whether the contact has a Windows Live + Space or not. + + + + + + + + + + + + + Seen is YYYY/MM/DD format. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A space (ASCII #32) separated list of properties that + have changed as part of an update request. The property + names don't always match the name of the associated + element. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/msnab_servicetypes.xsd b/MSNPSharp/Web References/MSNWS.MSNABSharingService/msnab_servicetypes.xsd new file mode 100644 index 0000000..c5923b5 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/msnab_servicetypes.xsd @@ -0,0 +1,599 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNABSharingService/msnab_sharingservice.wsdl b/MSNPSharp/Web References/MSNWS.MSNABSharingService/msnab_sharingservice.wsdl new file mode 100644 index 0000000..5e0d089 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNABSharingService/msnab_sharingservice.wsdl @@ -0,0 +1,606 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/Reference.cs b/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/Reference.cs new file mode 100644 index 0000000..1ecbf80 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/Reference.cs @@ -0,0 +1,624 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +// +// This source code was auto-generated by Microsoft.VSDesigner, Version 4.0.30319.42000. +// +#pragma warning disable 1591 + +namespace MSNPSharp.MSNWS.MSNOIMStoreService { + using System; + using System.Web.Services; + using System.Diagnostics; + using System.Web.Services.Protocols; + using System.Xml.Serialization; + using System.ComponentModel; + + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Web.Services.WebServiceBindingAttribute(Name="OIMBinding", Namespace="http://messenger.msn.com/ws/2004/09/oim/")] + public partial class OIMStoreService : System.Web.Services.Protocols.SoapHttpClientProtocol { + + private From fromValueField; + + private To toValueField; + + private Ticket ticketValueField; + + private SequenceType sequenceField; + + private SequenceAcknowledgment sequenceAcknowledgmentValueField; + + private System.Threading.SendOrPostCallback StoreOperationCompleted; + + private bool useDefaultCredentialsSetExplicitly; + + /// + public OIMStoreService() { + this.Url = "https://msnmsgr.escargot.chat/OimWS/oim.asmx"; + if ((this.IsLocalFileSystemWebService(this.Url) == true)) { + this.UseDefaultCredentials = true; + this.useDefaultCredentialsSetExplicitly = false; + } + else { + this.useDefaultCredentialsSetExplicitly = true; + } + } + + public From FromValue { + get { + return this.fromValueField; + } + set { + this.fromValueField = value; + } + } + + public To ToValue { + get { + return this.toValueField; + } + set { + this.toValueField = value; + } + } + + public Ticket TicketValue { + get { + return this.ticketValueField; + } + set { + this.ticketValueField = value; + } + } + + public SequenceType Sequence { + get { + return this.sequenceField; + } + set { + this.sequenceField = value; + } + } + + public SequenceAcknowledgment SequenceAcknowledgmentValue { + get { + return this.sequenceAcknowledgmentValueField; + } + set { + this.sequenceAcknowledgmentValueField = value; + } + } + + public new string Url { + get { + return base.Url; + } + set { + if ((((this.IsLocalFileSystemWebService(base.Url) == true) + && (this.useDefaultCredentialsSetExplicitly == false)) + && (this.IsLocalFileSystemWebService(value) == false))) { + base.UseDefaultCredentials = false; + } + base.Url = value; + } + } + + public new bool UseDefaultCredentials { + get { + return base.UseDefaultCredentials; + } + set { + base.UseDefaultCredentials = value; + this.useDefaultCredentialsSetExplicitly = true; + } + } + + /// + public event StoreCompletedEventHandler StoreCompleted; + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("Sequence")] + [System.Web.Services.Protocols.SoapHeaderAttribute("TicketValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("SequenceAcknowledgmentValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("FromValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ToValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://messenger.live.com/ws/2006/09/oim/Store2", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("StoreResponse", Namespace="http://messenger.msn.com/ws/2004/09/oim/")] + public StoreResultType Store([System.Xml.Serialization.XmlElementAttribute(Namespace="http://messenger.msn.com/ws/2004/09/oim/")] MessageType MessageType, [System.Xml.Serialization.XmlElementAttribute(Namespace="http://messenger.msn.com/ws/2004/09/oim/")] string Content) { + object[] results = this.Invoke("Store", new object[] { + MessageType, + Content}); + return ((StoreResultType)(results[0])); + } + + /// + public void StoreAsync(MessageType MessageType, string Content) { + this.StoreAsync(MessageType, Content, null); + } + + /// + public void StoreAsync(MessageType MessageType, string Content, object userState) { + if ((this.StoreOperationCompleted == null)) { + this.StoreOperationCompleted = new System.Threading.SendOrPostCallback(this.OnStoreOperationCompleted); + } + this.InvokeAsync("Store", new object[] { + MessageType, + Content}, this.StoreOperationCompleted, userState); + } + + private void OnStoreOperationCompleted(object arg) { + if ((this.StoreCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.StoreCompleted(this, new StoreCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + public new void CancelAsync(object userState) { + base.CancelAsync(userState); + } + + private bool IsLocalFileSystemWebService(string url) { + if (((url == null) + || (url == string.Empty))) { + return false; + } + System.Uri wsUri = new System.Uri(url); + if (((wsUri.Port >= 1024) + && (string.Compare(wsUri.Host, "localHost", System.StringComparison.OrdinalIgnoreCase) == 0))) { + return true; + } + return false; + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2003/03/rm")] + [System.Xml.Serialization.XmlRootAttribute("Sequence", Namespace="http://schemas.xmlsoap.org/ws/2003/03/rm", IsNullable=false)] + public partial class SequenceType : System.Web.Services.Protocols.SoapHeader { + + private AttributedURI identifierField; + + private ulong messageNumberField; + + private string lastMessageField; + + private System.Xml.XmlElement[] anyField; + + private System.Xml.XmlAttribute[] anyAttrField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://schemas.xmlsoap.org/ws/2002/07/utility")] + public AttributedURI Identifier { + get { + return this.identifierField; + } + set { + this.identifierField = value; + } + } + + /// + public ulong MessageNumber { + get { + return this.messageNumberField; + } + set { + this.messageNumberField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="ENTITY")] + public string LastMessage { + get { + return this.lastMessageField; + } + set { + this.lastMessageField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2002/07/utility")] + public partial class AttributedURI { + + private string idField; + + private System.Xml.XmlAttribute[] anyAttrField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(Form=System.Xml.Schema.XmlSchemaForm.Qualified, DataType="ID")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType="anyURI")] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://messenger.msn.com/ws/2004/09/oim/")] + public partial class StoreResultType { + + private string pointsConsumedField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string PointsConsumed { + get { + return this.pointsConsumedField; + } + set { + this.pointsConsumedField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://messenger.msn.com/ws/2004/09/oim/")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="http://messenger.msn.com/ws/2004/09/oim/", IsNullable=false)] + public partial class Ticket : System.Web.Services.Protocols.SoapHeader { + + private string passportField; + + private string appidField; + + private string lockkeyField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string passport { + get { + return this.passportField; + } + set { + this.passportField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string appid { + get { + return this.appidField; + } + set { + this.appidField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string lockkey { + get { + return this.lockkeyField; + } + set { + this.lockkeyField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://schemas.xmlsoap.org/ws/2003/03/rm")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="http://schemas.xmlsoap.org/ws/2003/03/rm", IsNullable=false)] + public partial class SequenceAcknowledgment : System.Web.Services.Protocols.SoapHeader { + + private AttributedURI identifierField; + + private SequenceAcknowledgmentAcknowledgmentRange[] acknowledgmentRangeField; + + private System.Xml.XmlElement[] anyField; + + private System.Xml.XmlAttribute[] anyAttrField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://schemas.xmlsoap.org/ws/2002/07/utility")] + public AttributedURI Identifier { + get { + return this.identifierField; + } + set { + this.identifierField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("AcknowledgmentRange")] + public SequenceAcknowledgmentAcknowledgmentRange[] AcknowledgmentRange { + get { + return this.acknowledgmentRangeField; + } + set { + this.acknowledgmentRangeField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://schemas.xmlsoap.org/ws/2003/03/rm")] + public partial class SequenceAcknowledgmentAcknowledgmentRange { + + private ulong upperField; + + private ulong lowerField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong Upper { + get { + return this.upperField; + } + set { + this.upperField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public ulong Lower { + get { + return this.lowerField; + } + set { + this.lowerField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://messenger.msn.com/ws/2004/09/oim/")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="http://messenger.msn.com/ws/2004/09/oim/", IsNullable=false)] + public partial class From : System.Web.Services.Protocols.SoapHeader { + + private string memberNameField; + + private string friendlyNameField; + + private string langField; + + private string proxyField; + + private string msnpVerField; + + private string buildVerField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string memberName { + get { + return this.memberNameField; + } + set { + this.memberNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string friendlyName { + get { + return this.friendlyNameField; + } + set { + this.friendlyNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(Form=System.Xml.Schema.XmlSchemaForm.Qualified, Namespace="http://www.w3.org/XML/1998/namespace")] + public string lang { + get { + return this.langField; + } + set { + this.langField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string proxy { + get { + return this.proxyField; + } + set { + this.proxyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string msnpVer { + get { + return this.msnpVerField; + } + set { + this.msnpVerField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string buildVer { + get { + return this.buildVerField; + } + set { + this.buildVerField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://messenger.msn.com/ws/2004/09/oim/")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="http://messenger.msn.com/ws/2004/09/oim/", IsNullable=false)] + public partial class To : System.Web.Services.Protocols.SoapHeader { + + private string memberNameField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string memberName { + get { + return this.memberNameField; + } + set { + this.memberNameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://messenger.msn.com/ws/2004/09/oim/")] + public enum MessageType { + + /// + text, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void StoreCompletedEventHandler(object sender, StoreCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class StoreCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal StoreCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public StoreResultType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((StoreResultType)(this.results[0])); + } + } + } +} + +#pragma warning restore 1591 \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/Reference.map b/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/Reference.map new file mode 100644 index 0000000..b0ff463 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/Reference.map @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/StoreResultType.datasource b/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/StoreResultType.datasource new file mode 100644 index 0000000..4a2f727 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/StoreResultType.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNOIMStoreService.StoreResultType, Web References.MSNWS.MSNOIMStoreService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/oim_servicetypes.xsd b/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/oim_servicetypes.xsd new file mode 100644 index 0000000..91c8711 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/oim_servicetypes.xsd @@ -0,0 +1,59 @@ + + + + + + + + + This field must be encoded according to RFC 2047. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/oim_ws.wsdl b/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/oim_ws.wsdl new file mode 100644 index 0000000..7339e74 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/oim_ws.wsdl @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/utility.xsd b/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/utility.xsd new file mode 100644 index 0000000..ef164dc --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/utility.xsd @@ -0,0 +1,202 @@ + + + + + +This type defines the fault code value for Timestamp message expiration. + + + + + + + + + +This type defines the fault code values for context-related faults. + + + + + + + + + + + + + +This global attribute supports annotating arbitrary elements with an ID. + + + + + + +This global attribute is used on extensions to distinguish mandatory vs. optional extensions. + + + + + + +Convenience attribute group used to simplify this schema. + + + + + + + + +This type is for elements whose [children] is a psuedo-dateTime and can have arbitrary attributes. + + + + + + + +This attribute indicates the actual schema type of the element [children]. +If the ValueType attribute is present, conforming processors must process the string value of [children] as if it were affiliated with the type indicated by this attribute. +If the ValueType attribute is absent, the implied value of this attribute is xsd:dateTime. + + + + + + + + + + +This type extends AnnotatedDateTime to add a Delay attribute. + + + + + + + +This attribute indicates the number of milliseconds that this actor processed this message. + + + + + + +This attribute indicates the intermediary that processed this message. + + + + + + + + + +This type is for elements whose [children] is an anyURI and can have arbitrary attributes. + + + + + + + + + + + +This complex type ties together the timestamp related elements into a composite type. + + + + + + + + + + + + + + + +This element allows Timestamps to be applied anywhere element wildcards are present, +including as a SOAP header. + + + + + + +This element allows an expiration time to be applied anywhere element wildcards are present. + + + + + + +This element allows a creation time to be applied anywhere element wildcards are present. + + + + + + +This element allows the ReceviedType to be applied anywhere element wildcards are present, including a Timestamp header. + + + + + + + +This type is the generic base type for context headers. + + + + + + + + + + + +This element allows Contexts to be applied anywhere element wildcards are present, +including as a SOAP header. + + + + + + + + + + + + + + + +This complex type defines a lightweight type for transmitting ports. + + + + + + + + + + + +This element allows port references to be applied anywhere element wildcards are present. + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/wsrm.xsd b/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/wsrm.xsd new file mode 100644 index 0000000..a5b346b --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNOIMStoreService/wsrm.xsd @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNRSIService/DeleteMessagesResponseType.datasource b/MSNPSharp/Web References/MSNWS.MSNRSIService/DeleteMessagesResponseType.datasource new file mode 100644 index 0000000..2c6747b --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNRSIService/DeleteMessagesResponseType.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNRSIService.DeleteMessagesResponseType, Web References.MSNWS.MSNRSIService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNRSIService/GetMessageResponseType.datasource b/MSNPSharp/Web References/MSNWS.MSNRSIService/GetMessageResponseType.datasource new file mode 100644 index 0000000..10b4773 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNRSIService/GetMessageResponseType.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNRSIService.GetMessageResponseType, Web References.MSNWS.MSNRSIService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNRSIService/Reference.cs b/MSNPSharp/Web References/MSNWS.MSNRSIService/Reference.cs new file mode 100644 index 0000000..c9faed6 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNRSIService/Reference.cs @@ -0,0 +1,651 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +// +// This source code was auto-generated by Microsoft.VSDesigner, Version 4.0.30319.42000. +// +#pragma warning disable 1591 + +namespace MSNPSharp.MSNWS.MSNRSIService { + using System; + using System.Web.Services; + using System.Diagnostics; + using System.Web.Services.Protocols; + using System.Xml.Serialization; + using System.ComponentModel; + + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Web.Services.WebServiceBindingAttribute(Name="RSIBinding", Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(GetMetadataResponseType))] + public partial class RSIService : System.Web.Services.Protocols.SoapHttpClientProtocol { + + private PassportCookie passportCookieValueField; + + private System.Threading.SendOrPostCallback GetMetadataOperationCompleted; + + private System.Threading.SendOrPostCallback GetMessageOperationCompleted; + + private System.Threading.SendOrPostCallback DeleteMessagesOperationCompleted; + + private bool useDefaultCredentialsSetExplicitly; + + /// + public RSIService() { + this.Url = "https://msnmsgr.escargot.chat/rsi/rsi.asmx"; + if ((this.IsLocalFileSystemWebService(this.Url) == true)) { + this.UseDefaultCredentials = true; + this.useDefaultCredentialsSetExplicitly = false; + } + else { + this.useDefaultCredentialsSetExplicitly = true; + } + } + + public PassportCookie PassportCookieValue { + get { + return this.passportCookieValueField; + } + set { + this.passportCookieValueField = value; + } + } + + public new string Url { + get { + return base.Url; + } + set { + if ((((this.IsLocalFileSystemWebService(base.Url) == true) + && (this.useDefaultCredentialsSetExplicitly == false)) + && (this.IsLocalFileSystemWebService(value) == false))) { + base.UseDefaultCredentials = false; + } + base.Url = value; + } + } + + public new bool UseDefaultCredentials { + get { + return base.UseDefaultCredentials; + } + set { + base.UseDefaultCredentials = value; + this.useDefaultCredentialsSetExplicitly = true; + } + } + + /// + public event GetMetadataCompletedEventHandler GetMetadataCompleted; + + /// + public event GetMessageCompletedEventHandler GetMessageCompleted; + + /// + public event DeleteMessagesCompletedEventHandler DeleteMessagesCompleted; + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("PassportCookieValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.hotmail.msn.com/ws/2004/09/oim/rsi/GetMetadata", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("GetMetadataResponse", Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] + public object GetMetadata([System.Xml.Serialization.XmlElementAttribute("GetMetadata", Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] GetMetadataRequestType GetMetadata1) { + object[] results = this.Invoke("GetMetadata", new object[] { + GetMetadata1}); + return ((object)(results[0])); + } + + /// + public void GetMetadataAsync(GetMetadataRequestType GetMetadata1) { + this.GetMetadataAsync(GetMetadata1, null); + } + + /// + public void GetMetadataAsync(GetMetadataRequestType GetMetadata1, object userState) { + if ((this.GetMetadataOperationCompleted == null)) { + this.GetMetadataOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetMetadataOperationCompleted); + } + this.InvokeAsync("GetMetadata", new object[] { + GetMetadata1}, this.GetMetadataOperationCompleted, userState); + } + + private void OnGetMetadataOperationCompleted(object arg) { + if ((this.GetMetadataCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.GetMetadataCompleted(this, new GetMetadataCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("PassportCookieValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.hotmail.msn.com/ws/2004/09/oim/rsi/GetMessage", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("GetMessageResponse", Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] + public GetMessageResponseType GetMessage([System.Xml.Serialization.XmlElementAttribute("GetMessage", Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] GetMessageRequestType GetMessage1) { + object[] results = this.Invoke("GetMessage", new object[] { + GetMessage1}); + return ((GetMessageResponseType)(results[0])); + } + + /// + public void GetMessageAsync(GetMessageRequestType GetMessage1) { + this.GetMessageAsync(GetMessage1, null); + } + + /// + public void GetMessageAsync(GetMessageRequestType GetMessage1, object userState) { + if ((this.GetMessageOperationCompleted == null)) { + this.GetMessageOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetMessageOperationCompleted); + } + this.InvokeAsync("GetMessage", new object[] { + GetMessage1}, this.GetMessageOperationCompleted, userState); + } + + private void OnGetMessageOperationCompleted(object arg) { + if ((this.GetMessageCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.GetMessageCompleted(this, new GetMessageCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("PassportCookieValue")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.hotmail.msn.com/ws/2004/09/oim/rsi/DeleteMessages", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("DeleteMessagesResponse", Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] + public DeleteMessagesResponseType DeleteMessages([System.Xml.Serialization.XmlElementAttribute("DeleteMessages", Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] DeleteMessagesRequestType DeleteMessages1) { + object[] results = this.Invoke("DeleteMessages", new object[] { + DeleteMessages1}); + return ((DeleteMessagesResponseType)(results[0])); + } + + /// + public void DeleteMessagesAsync(DeleteMessagesRequestType DeleteMessages1) { + this.DeleteMessagesAsync(DeleteMessages1, null); + } + + /// + public void DeleteMessagesAsync(DeleteMessagesRequestType DeleteMessages1, object userState) { + if ((this.DeleteMessagesOperationCompleted == null)) { + this.DeleteMessagesOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDeleteMessagesOperationCompleted); + } + this.InvokeAsync("DeleteMessages", new object[] { + DeleteMessages1}, this.DeleteMessagesOperationCompleted, userState); + } + + private void OnDeleteMessagesOperationCompleted(object arg) { + if ((this.DeleteMessagesCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.DeleteMessagesCompleted(this, new DeleteMessagesCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + public new void CancelAsync(object userState) { + base.CancelAsync(userState); + } + + private bool IsLocalFileSystemWebService(string url) { + if (((url == null) + || (url == string.Empty))) { + return false; + } + System.Uri wsUri = new System.Uri(url); + if (((wsUri.Port >= 1024) + && (string.Compare(wsUri.Host, "localHost", System.StringComparison.OrdinalIgnoreCase) == 0))) { + return true; + } + return false; + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi", IsNullable=false)] + public partial class PassportCookie : System.Web.Services.Protocols.SoapHeader { + + private string tField; + + private string pField; + + /// + public string t { + get { + return this.tField; + } + set { + this.tField = value; + } + } + + /// + public string p { + get { + return this.pField; + } + set { + this.pField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] + public partial class DeleteMessagesResponseType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] + public partial class DeleteMessagesRequestType { + + private string[] messageIdsField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("messageId", IsNullable=false)] + public string[] messageIds { + get { + return this.messageIdsField; + } + set { + this.messageIdsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] + public partial class GetMessageResponseType { + + private string getMessageResultField; + + /// + public string GetMessageResult { + get { + return this.getMessageResultField; + } + set { + this.getMessageResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] + public partial class GetMessageRequestType { + + private string messageIdField; + + private bool alsoMarkAsReadField; + + /// + public string messageId { + get { + return this.messageIdField; + } + set { + this.messageIdField = value; + } + } + + /// + public bool alsoMarkAsRead { + get { + return this.alsoMarkAsReadField; + } + set { + this.alsoMarkAsReadField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] + public partial class GetMetadataResponseType { + + private MetaData mdField; + + /// + public MetaData MD { + get { + return this.mdField; + } + set { + this.mdField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] + public partial class MetaData { + + private MetadataMessage[] mField; + + private MetaDataQ qField; + + /// + [System.Xml.Serialization.XmlElementAttribute("M")] + public MetadataMessage[] M { + get { + return this.mField; + } + set { + this.mField = value; + } + } + + /// + public MetaDataQ Q { + get { + return this.qField; + } + set { + this.qField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] + public partial class MetadataMessage { + + private string tField; + + private string sField; + + private System.DateTime rtField; + + private bool rtFieldSpecified; + + private bool rsField; + + private string szField; + + private string eField; + + private string iField; + + private string fField; + + private string nField; + + private string suField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string T { + get { + return this.tField; + } + set { + this.tField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string S { + get { + return this.sField; + } + set { + this.sField = value; + } + } + + /// + public System.DateTime RT { + get { + return this.rtField; + } + set { + this.rtField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool RTSpecified { + get { + return this.rtFieldSpecified; + } + set { + this.rtFieldSpecified = value; + } + } + + /// + public bool RS { + get { + return this.rsField; + } + set { + this.rsField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string SZ { + get { + return this.szField; + } + set { + this.szField = value; + } + } + + /// + public string E { + get { + return this.eField; + } + set { + this.eField = value; + } + } + + /// + public string I { + get { + return this.iField; + } + set { + this.iField = value; + } + } + + /// + public string F { + get { + return this.fField; + } + set { + this.fField = value; + } + } + + /// + public string N { + get { + return this.nField; + } + set { + this.nField = value; + } + } + + /// + public string SU { + get { + return this.suField; + } + set { + this.suField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] + public partial class MetaDataQ { + + private string qTMField; + + private string qNMField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string QTM { + get { + return this.qTMField; + } + set { + this.qTMField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string QNM { + get { + return this.qNMField; + } + set { + this.qNMField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.hotmail.msn.com/ws/2004/09/oim/rsi")] + public partial class GetMetadataRequestType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void GetMetadataCompletedEventHandler(object sender, GetMetadataCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class GetMetadataCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal GetMetadataCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public object Result { + get { + this.RaiseExceptionIfNecessary(); + return ((object)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void GetMessageCompletedEventHandler(object sender, GetMessageCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class GetMessageCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal GetMessageCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public GetMessageResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((GetMessageResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void DeleteMessagesCompletedEventHandler(object sender, DeleteMessagesCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class DeleteMessagesCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal DeleteMessagesCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public DeleteMessagesResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((DeleteMessagesResponseType)(this.results[0])); + } + } + } +} + +#pragma warning restore 1591 \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNRSIService/Reference.map b/MSNPSharp/Web References/MSNWS.MSNRSIService/Reference.map new file mode 100644 index 0000000..f0dbcc8 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNRSIService/Reference.map @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNRSIService/rsi_datatypes.xsd b/MSNPSharp/Web References/MSNWS.MSNRSIService/rsi_datatypes.xsd new file mode 100644 index 0000000..04dcbbb --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNRSIService/rsi_datatypes.xsd @@ -0,0 +1,66 @@ + + + + + + + 11 + + + + + 6 + + + + + The time the message was received. + + + + + Read set. + + + + + The size of the message. + + + + + The passport name of the sender. + + + + + The unique ID for this message. Seems to be a GUID. + + + + + Hotmail folder GUID. 000009 or .!!OIM + + + + + RFC 2047-encoded friendly name of the sender. + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNRSIService/rsi_faulttypes.xsd b/MSNPSharp/Web References/MSNWS.MSNRSIService/rsi_faulttypes.xsd new file mode 100644 index 0000000..f8991ab --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNRSIService/rsi_faulttypes.xsd @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNRSIService/rsi_servicetypes.xsd b/MSNPSharp/Web References/MSNWS.MSNRSIService/rsi_servicetypes.xsd new file mode 100644 index 0000000..62dae1f --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNRSIService/rsi_servicetypes.xsd @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNRSIService/rsi_ws.wsdl b/MSNPSharp/Web References/MSNWS.MSNRSIService/rsi_ws.wsdl new file mode 100644 index 0000000..330ff29 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNRSIService/rsi_ws.wsdl @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/Reference.cs b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/Reference.cs new file mode 100644 index 0000000..7b9c909 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/Reference.cs @@ -0,0 +1,5236 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +// +// This source code was auto-generated by Microsoft.VSDesigner, Version 4.0.30319.42000. +// +#pragma warning disable 1591 + +namespace MSNPSharp.MSNWS.MSNSecurityTokenService { + using System; + using System.Web.Services; + using System.Diagnostics; + using System.Web.Services.Protocols; + using System.Xml.Serialization; + using System.ComponentModel; + + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Web.Services.WebServiceBindingAttribute(Name="SecurityTokenServicePortBinding", Namespace="http://schemas.microsoft.com/Passport/SoapServices/PPCRL")] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(NotUnderstoodType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(Fault))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(Envelope))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DerivedKeyTokenType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(SecurityContextTokenType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(SignaturePropertiesType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ManifestType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(AttributeDesignatorType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(EndpointReferenceType1))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(ProblemActionType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(errorType))] + public partial class SecurityTokenService : System.Web.Services.Protocols.SoapHttpClientProtocol { + + private SecurityHeaderType securityField; + + private AuthInfoType authInfoField; + + private Action actionValueField; + + private To toValueField; + + private AttributedURIType messageIDField; + + private ppHeaderType ppField; + + private System.Threading.SendOrPostCallback RequestMultipleSecurityTokensOperationCompleted; + + private AttributedURI actionField; + + private Relationship relatesToField; + + private RelatesToType relatesTo1Field; + + private System.Threading.SendOrPostCallback RequestSecurityTokenOperationCompleted; + + private bool useDefaultCredentialsSetExplicitly; + + /// + public SecurityTokenService() { + this.SoapVersion = System.Web.Services.Protocols.SoapProtocolVersion.Soap12; + this.Url = "https://msnmsgr.escargot.chat/RST2.srf"; + if ((this.IsLocalFileSystemWebService(this.Url) == true)) { + this.UseDefaultCredentials = true; + this.useDefaultCredentialsSetExplicitly = false; + } + else { + this.useDefaultCredentialsSetExplicitly = true; + } + } + + public SecurityHeaderType Security { + get { + return this.securityField; + } + set { + this.securityField = value; + } + } + + public AuthInfoType AuthInfo { + get { + return this.authInfoField; + } + set { + this.authInfoField = value; + } + } + + public Action ActionValue { + get { + return this.actionValueField; + } + set { + this.actionValueField = value; + } + } + + public To ToValue { + get { + return this.toValueField; + } + set { + this.toValueField = value; + } + } + + public AttributedURIType MessageID { + get { + return this.messageIDField; + } + set { + this.messageIDField = value; + } + } + + public ppHeaderType pp { + get { + return this.ppField; + } + set { + this.ppField = value; + } + } + + public AttributedURI Action { + get { + return this.actionField; + } + set { + this.actionField = value; + } + } + + public Relationship RelatesTo { + get { + return this.relatesToField; + } + set { + this.relatesToField = value; + } + } + + public RelatesToType RelatesTo1 { + get { + return this.relatesTo1Field; + } + set { + this.relatesTo1Field = value; + } + } + + public new string Url { + get { + return base.Url; + } + set { + if ((((this.IsLocalFileSystemWebService(base.Url) == true) + && (this.useDefaultCredentialsSetExplicitly == false)) + && (this.IsLocalFileSystemWebService(value) == false))) { + base.UseDefaultCredentials = false; + } + base.Url = value; + } + } + + public new bool UseDefaultCredentials { + get { + return base.UseDefaultCredentials; + } + set { + base.UseDefaultCredentials = value; + this.useDefaultCredentialsSetExplicitly = true; + } + } + + /// + public event RequestMultipleSecurityTokensCompletedEventHandler RequestMultipleSecurityTokensCompleted; + + /// + public event RequestSecurityTokenCompletedEventHandler RequestSecurityTokenCompleted; + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("Security", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapHeaderAttribute("MessageID")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ToValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapHeaderAttribute("ActionValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapHeaderAttribute("pp", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("AuthInfo")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlArrayAttribute("RequestSecurityTokenResponseCollection", Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] + [return: System.Xml.Serialization.XmlArrayItemAttribute("RequestSecurityTokenResponse", IsNullable=false)] + public RequestSecurityTokenResponseType[] RequestMultipleSecurityTokens([System.Xml.Serialization.XmlElementAttribute("RequestMultipleSecurityTokens", Namespace="http://schemas.microsoft.com/Passport/SoapServices/PPCRL")] RequestMultipleSecurityTokensType RequestMultipleSecurityTokens1) { + object[] results = this.Invoke("RequestMultipleSecurityTokens", new object[] { + RequestMultipleSecurityTokens1}); + return ((RequestSecurityTokenResponseType[])(results[0])); + } + + /// + public void RequestMultipleSecurityTokensAsync(RequestMultipleSecurityTokensType RequestMultipleSecurityTokens1) { + this.RequestMultipleSecurityTokensAsync(RequestMultipleSecurityTokens1, null); + } + + /// + public void RequestMultipleSecurityTokensAsync(RequestMultipleSecurityTokensType RequestMultipleSecurityTokens1, object userState) { + if ((this.RequestMultipleSecurityTokensOperationCompleted == null)) { + this.RequestMultipleSecurityTokensOperationCompleted = new System.Threading.SendOrPostCallback(this.OnRequestMultipleSecurityTokensOperationCompleted); + } + this.InvokeAsync("RequestMultipleSecurityTokens", new object[] { + RequestMultipleSecurityTokens1}, this.RequestMultipleSecurityTokensOperationCompleted, userState); + } + + private void OnRequestMultipleSecurityTokensOperationCompleted(object arg) { + if ((this.RequestMultipleSecurityTokensCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.RequestMultipleSecurityTokensCompleted(this, new RequestMultipleSecurityTokensCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("Security")] + [System.Web.Services.Protocols.SoapHeaderAttribute("RelatesTo", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("Action", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("MessageID")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ToValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("ActionValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapHeaderAttribute("pp", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("RelatesTo1", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("AuthInfo")] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("RequestSecurityTokenResponse", Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] + public RequestSecurityTokenResponseType RequestSecurityToken([System.Xml.Serialization.XmlElementAttribute("RequestSecurityToken", Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] RequestSecurityTokenType RequestSecurityToken1) { + object[] results = this.Invoke("RequestSecurityToken", new object[] { + RequestSecurityToken1}); + return ((RequestSecurityTokenResponseType)(results[0])); + } + + /// + public void RequestSecurityTokenAsync(RequestSecurityTokenType RequestSecurityToken1) { + this.RequestSecurityTokenAsync(RequestSecurityToken1, null); + } + + /// + public void RequestSecurityTokenAsync(RequestSecurityTokenType RequestSecurityToken1, object userState) { + if ((this.RequestSecurityTokenOperationCompleted == null)) { + this.RequestSecurityTokenOperationCompleted = new System.Threading.SendOrPostCallback(this.OnRequestSecurityTokenOperationCompleted); + } + this.InvokeAsync("RequestSecurityToken", new object[] { + RequestSecurityToken1}, this.RequestSecurityTokenOperationCompleted, userState); + } + + private void OnRequestSecurityTokenOperationCompleted(object arg) { + if ((this.RequestSecurityTokenCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.RequestSecurityTokenCompleted(this, new RequestSecurityTokenCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + public new void CancelAsync(object userState) { + base.CancelAsync(userState); + } + + private bool IsLocalFileSystemWebService(string url) { + if (((url == null) + || (url == string.Empty))) { + return false; + } + System.Uri wsUri = new System.Uri(url); + if (((wsUri.Port >= 1024) + && (string.Compare(wsUri.Host, "localHost", System.StringComparison.OrdinalIgnoreCase) == 0))) { + return true; + } + return false; + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" + + "")] + [System.Xml.Serialization.XmlRootAttribute("Security", Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" + + "", IsNullable=false)] + public partial class SecurityHeaderType : System.Web.Services.Protocols.SoapHeader { + + private UsernameTokenType usernameTokenField; + + private TimestampType timestampField; + + private AssertionType assertionField; + + /// + public UsernameTokenType UsernameToken { + get { + return this.usernameTokenField; + } + set { + this.usernameTokenField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xs" + + "d")] + public TimestampType Timestamp { + get { + return this.timestampField; + } + set { + this.timestampField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public AssertionType Assertion { + get { + return this.assertionField; + } + set { + this.assertionField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" + + "")] + public partial class UsernameTokenType { + + private AttributedString usernameField; + + private PasswordString passwordField; + + private string idField; + + /// + public AttributedString Username { + get { + return this.usernameField; + } + set { + this.usernameField = value; + } + } + + /// + public PasswordString Password { + get { + return this.passwordField; + } + set { + this.passwordField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(Form=System.Xml.Schema.XmlSchemaForm.Qualified, Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xs" + + "d", DataType="ID")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(EncodedString))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BinarySecurityTokenType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(KeyIdentifierType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(PasswordString))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" + + "")] + public partial class AttributedString { + + private string idField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class ActionType { + + private string namespaceField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string Namespace { + get { + return this.namespaceField; + } + set { + this.namespaceField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2003/05/soap-envelope")] + public partial class SupportedEnvType { + + private System.Xml.XmlQualifiedName qnameField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public System.Xml.XmlQualifiedName qname { + get { + return this.qnameField; + } + set { + this.qnameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2003/05/soap-envelope")] + public partial class NotUnderstoodType { + + private System.Xml.XmlQualifiedName qnameField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public System.Xml.XmlQualifiedName qname { + get { + return this.qnameField; + } + set { + this.qnameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2003/05/soap-envelope")] + public partial class detail { + + private System.Xml.XmlElement[] anyField; + + private System.Xml.XmlAttribute[] anyAttrField; + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2003/05/soap-envelope")] + public partial class reasontext { + + private string langField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(Form=System.Xml.Schema.XmlSchemaForm.Qualified, Namespace="http://www.w3.org/XML/1998/namespace")] + public string lang { + get { + return this.langField; + } + set { + this.langField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2003/05/soap-envelope")] + public partial class subcode { + + private System.Xml.XmlQualifiedName valueField; + + private subcode subcodeField; + + /// + public System.Xml.XmlQualifiedName Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + + /// + public subcode Subcode { + get { + return this.subcodeField; + } + set { + this.subcodeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2003/05/soap-envelope")] + public partial class faultcode { + + private System.Xml.XmlQualifiedName valueField; + + private subcode subcodeField; + + /// + public System.Xml.XmlQualifiedName Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + + /// + public subcode Subcode { + get { + return this.subcodeField; + } + set { + this.subcodeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2003/05/soap-envelope")] + public partial class Fault { + + private faultcode codeField; + + private reasontext[] reasonField; + + private string nodeField; + + private string roleField; + + private detail detailField; + + /// + public faultcode Code { + get { + return this.codeField; + } + set { + this.codeField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Text", IsNullable=false)] + public reasontext[] Reason { + get { + return this.reasonField; + } + set { + this.reasonField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="anyURI")] + public string Node { + get { + return this.nodeField; + } + set { + this.nodeField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="anyURI")] + public string Role { + get { + return this.roleField; + } + set { + this.roleField = value; + } + } + + /// + public detail Detail { + get { + return this.detailField; + } + set { + this.detailField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2003/05/soap-envelope")] + public partial class Body { + + private System.Xml.XmlElement[] anyField; + + private System.Xml.XmlAttribute[] anyAttrField; + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2003/05/soap-envelope")] + public partial class Header { + + private System.Xml.XmlElement[] anyField; + + private System.Xml.XmlAttribute[] anyAttrField; + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2003/05/soap-envelope")] + public partial class Envelope { + + private Header headerField; + + private Body bodyField; + + private System.Xml.XmlAttribute[] anyAttrField; + + /// + public Header Header { + get { + return this.headerField; + } + set { + this.headerField = value; + } + } + + /// + public Body Body { + get { + return this.bodyField; + } + set { + this.bodyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2005/02/sc")] + public partial class PropertiesType { + + private System.Xml.XmlElement[] anyField; + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2005/02/sc")] + public partial class DerivedKeyTokenType { + + private SecurityTokenReferenceType securityTokenReferenceField; + + private PropertiesType propertiesField; + + private ulong generationField; + + private bool generationFieldSpecified; + + private ulong offsetField; + + private bool offsetFieldSpecified; + + private ulong lengthField; + + private bool lengthFieldSpecified; + + private string labelField; + + private byte[] nonceField; + + private string idField; + + private string algorithmField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" + + "")] + public SecurityTokenReferenceType SecurityTokenReference { + get { + return this.securityTokenReferenceField; + } + set { + this.securityTokenReferenceField = value; + } + } + + /// + public PropertiesType Properties { + get { + return this.propertiesField; + } + set { + this.propertiesField = value; + } + } + + /// + public ulong Generation { + get { + return this.generationField; + } + set { + this.generationField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool GenerationSpecified { + get { + return this.generationFieldSpecified; + } + set { + this.generationFieldSpecified = value; + } + } + + /// + public ulong Offset { + get { + return this.offsetField; + } + set { + this.offsetField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool OffsetSpecified { + get { + return this.offsetFieldSpecified; + } + set { + this.offsetFieldSpecified = value; + } + } + + /// + public ulong Length { + get { + return this.lengthField; + } + set { + this.lengthField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool LengthSpecified { + get { + return this.lengthFieldSpecified; + } + set { + this.lengthFieldSpecified = value; + } + } + + /// + public string Label { + get { + return this.labelField; + } + set { + this.labelField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] + public byte[] Nonce { + get { + return this.nonceField; + } + set { + this.nonceField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(Form=System.Xml.Schema.XmlSchemaForm.Qualified, Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xs" + + "d", DataType="ID")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string Algorithm { + get { + return this.algorithmField; + } + set { + this.algorithmField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" + + "")] + public partial class SecurityTokenReferenceType { + + private System.Xml.XmlElement anyField; + + private ReferenceType[] referenceField; + + private string idField; + + private string usageField; + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("Reference")] + public ReferenceType[] Reference { + get { + return this.referenceField; + } + set { + this.referenceField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string Usage { + get { + return this.usageField; + } + set { + this.usageField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" + + "")] + public partial class ReferenceType { + + private string uRIField; + + private System.Xml.XmlQualifiedName valueTypeField; + + private System.Xml.XmlAttribute[] anyAttrField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string URI { + get { + return this.uRIField; + } + set { + this.uRIField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public System.Xml.XmlQualifiedName ValueType { + get { + return this.valueTypeField; + } + set { + this.valueTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2005/02/sc")] + public partial class SecurityContextTokenType { + + private System.Xml.XmlElement[] anyField; + + private string idField; + + private System.Xml.XmlAttribute[] anyAttrField; + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(Form=System.Xml.Schema.XmlSchemaForm.Qualified, Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xs" + + "d", DataType="ID")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class SignaturePropertyType { + + private System.Xml.XmlNode[] anyField; + + private string targetField; + + private string idField; + + /// + [System.Xml.Serialization.XmlTextAttribute()] + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlNode[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string Target { + get { + return this.targetField; + } + set { + this.targetField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="ID")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class SignaturePropertiesType { + + private SignaturePropertyType[] signaturePropertyField; + + private string idField; + + /// + [System.Xml.Serialization.XmlElementAttribute("SignatureProperty")] + public SignaturePropertyType[] SignatureProperty { + get { + return this.signaturePropertyField; + } + set { + this.signaturePropertyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="ID")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class ManifestType { + + private ReferenceType1[] referenceField; + + private string idField; + + /// + [System.Xml.Serialization.XmlElementAttribute("Reference")] + public ReferenceType1[] Reference { + get { + return this.referenceField; + } + set { + this.referenceField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="ID")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(TypeName="ReferenceType", Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class ReferenceType1 { + + private TransformType[] transformsField; + + private DigestMethodType digestMethodField; + + private byte[] digestValueField; + + private string idField; + + private string uRIField; + + private string typeField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Transform", IsNullable=false)] + public TransformType[] Transforms { + get { + return this.transformsField; + } + set { + this.transformsField = value; + } + } + + /// + public DigestMethodType DigestMethod { + get { + return this.digestMethodField; + } + set { + this.digestMethodField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] + public byte[] DigestValue { + get { + return this.digestValueField; + } + set { + this.digestValueField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="ID")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string URI { + get { + return this.uRIField; + } + set { + this.uRIField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string Type { + get { + return this.typeField; + } + set { + this.typeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class TransformType { + + private System.Xml.XmlNode[] anyField; + + private string[] xPathField; + + private string algorithmField; + + /// + [System.Xml.Serialization.XmlTextAttribute()] + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlNode[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("XPath")] + public string[] XPath { + get { + return this.xPathField; + } + set { + this.xPathField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string Algorithm { + get { + return this.algorithmField; + } + set { + this.algorithmField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class DigestMethodType { + + private System.Xml.XmlNode[] anyField; + + private string algorithmField; + + /// + [System.Xml.Serialization.XmlTextAttribute()] + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlNode[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string Algorithm { + get { + return this.algorithmField; + } + set { + this.algorithmField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class ObjectType { + + private System.Xml.XmlNode[] anyField; + + private string idField; + + private string mimeTypeField; + + private string encodingField; + + /// + [System.Xml.Serialization.XmlTextAttribute()] + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlNode[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="ID")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string MimeType { + get { + return this.mimeTypeField; + } + set { + this.mimeTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string Encoding { + get { + return this.encodingField; + } + set { + this.encodingField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class SignatureValueType { + + private string idField; + + private byte[] valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="ID")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType="base64Binary")] + public byte[] Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class SignatureMethodType { + + private string hMACOutputLengthField; + + private System.Xml.XmlNode[] anyField; + + private string algorithmField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string HMACOutputLength { + get { + return this.hMACOutputLengthField; + } + set { + this.hMACOutputLengthField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlNode[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string Algorithm { + get { + return this.algorithmField; + } + set { + this.algorithmField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class CanonicalizationMethodType { + + private System.Xml.XmlNode[] anyField; + + private string algorithmField; + + /// + [System.Xml.Serialization.XmlTextAttribute()] + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlNode[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string Algorithm { + get { + return this.algorithmField; + } + set { + this.algorithmField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class SignedInfoType { + + private CanonicalizationMethodType canonicalizationMethodField; + + private SignatureMethodType signatureMethodField; + + private ReferenceType1[] referenceField; + + private string idField; + + /// + public CanonicalizationMethodType CanonicalizationMethod { + get { + return this.canonicalizationMethodField; + } + set { + this.canonicalizationMethodField = value; + } + } + + /// + public SignatureMethodType SignatureMethod { + get { + return this.signatureMethodField; + } + set { + this.signatureMethodField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("Reference")] + public ReferenceType1[] Reference { + get { + return this.referenceField; + } + set { + this.referenceField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="ID")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class SignatureType { + + private SignedInfoType signedInfoField; + + private SignatureValueType signatureValueField; + + private KeyInfoType keyInfoField; + + private ObjectType[] objectField; + + private string idField; + + /// + public SignedInfoType SignedInfo { + get { + return this.signedInfoField; + } + set { + this.signedInfoField = value; + } + } + + /// + public SignatureValueType SignatureValue { + get { + return this.signatureValueField; + } + set { + this.signatureValueField = value; + } + } + + /// + public KeyInfoType KeyInfo { + get { + return this.keyInfoField; + } + set { + this.keyInfoField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("Object")] + public ObjectType[] Object { + get { + return this.objectField; + } + set { + this.objectField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="ID")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class KeyInfoType { + + private string[] keyNameField; + + private KeyValueType[] keyValueField; + + private RetrievalMethodType[] retrievalMethodField; + + private X509DataType[] x509DataField; + + private PGPDataType[] pGPDataField; + + private SPKIDataType[] sPKIDataField; + + private string[] mgmtDataField; + + private System.Xml.XmlNode[] anyField; + + private string idField; + + /// + [System.Xml.Serialization.XmlElementAttribute("KeyName")] + public string[] KeyName { + get { + return this.keyNameField; + } + set { + this.keyNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("KeyValue")] + public KeyValueType[] KeyValue { + get { + return this.keyValueField; + } + set { + this.keyValueField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("RetrievalMethod")] + public RetrievalMethodType[] RetrievalMethod { + get { + return this.retrievalMethodField; + } + set { + this.retrievalMethodField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("X509Data")] + public X509DataType[] X509Data { + get { + return this.x509DataField; + } + set { + this.x509DataField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("PGPData")] + public PGPDataType[] PGPData { + get { + return this.pGPDataField; + } + set { + this.pGPDataField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("SPKIData")] + public SPKIDataType[] SPKIData { + get { + return this.sPKIDataField; + } + set { + this.sPKIDataField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("MgmtData")] + public string[] MgmtData { + get { + return this.mgmtDataField; + } + set { + this.mgmtDataField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlNode[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="ID")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class KeyValueType { + + private DSAKeyValueType dSAKeyValueField; + + private RSAKeyValueType rSAKeyValueField; + + private System.Xml.XmlNode[] anyField; + + /// + public DSAKeyValueType DSAKeyValue { + get { + return this.dSAKeyValueField; + } + set { + this.dSAKeyValueField = value; + } + } + + /// + public RSAKeyValueType RSAKeyValue { + get { + return this.rSAKeyValueField; + } + set { + this.rSAKeyValueField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlNode[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class DSAKeyValueType { + + private byte[] pField; + + private byte[] qField; + + private byte[] gField; + + private byte[] yField; + + private byte[] jField; + + private byte[] seedField; + + private byte[] pgenCounterField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] + public byte[] P { + get { + return this.pField; + } + set { + this.pField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] + public byte[] Q { + get { + return this.qField; + } + set { + this.qField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] + public byte[] G { + get { + return this.gField; + } + set { + this.gField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] + public byte[] Y { + get { + return this.yField; + } + set { + this.yField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] + public byte[] J { + get { + return this.jField; + } + set { + this.jField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] + public byte[] Seed { + get { + return this.seedField; + } + set { + this.seedField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] + public byte[] PgenCounter { + get { + return this.pgenCounterField; + } + set { + this.pgenCounterField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class RSAKeyValueType { + + private byte[] modulusField; + + private byte[] exponentField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] + public byte[] Modulus { + get { + return this.modulusField; + } + set { + this.modulusField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] + public byte[] Exponent { + get { + return this.exponentField; + } + set { + this.exponentField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class RetrievalMethodType { + + private TransformType[] transformsField; + + private string uRIField; + + private string typeField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Transform", IsNullable=false)] + public TransformType[] Transforms { + get { + return this.transformsField; + } + set { + this.transformsField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string URI { + get { + return this.uRIField; + } + set { + this.uRIField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string Type { + get { + return this.typeField; + } + set { + this.typeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class X509DataType { + + private X509IssuerSerialType[] x509IssuerSerialField; + + private byte[][] x509SKIField; + + private string[] x509SubjectNameField; + + private byte[][] x509CertificateField; + + private byte[][] x509CRLField; + + private System.Xml.XmlElement anyField; + + /// + [System.Xml.Serialization.XmlElementAttribute("X509IssuerSerial")] + public X509IssuerSerialType[] X509IssuerSerial { + get { + return this.x509IssuerSerialField; + } + set { + this.x509IssuerSerialField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("X509SKI", DataType="base64Binary")] + public byte[][] X509SKI { + get { + return this.x509SKIField; + } + set { + this.x509SKIField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("X509SubjectName")] + public string[] X509SubjectName { + get { + return this.x509SubjectNameField; + } + set { + this.x509SubjectNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("X509Certificate", DataType="base64Binary")] + public byte[][] X509Certificate { + get { + return this.x509CertificateField; + } + set { + this.x509CertificateField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("X509CRL", DataType="base64Binary")] + public byte[][] X509CRL { + get { + return this.x509CRLField; + } + set { + this.x509CRLField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class X509IssuerSerialType { + + private string x509IssuerNameField; + + private string x509SerialNumberField; + + /// + public string X509IssuerName { + get { + return this.x509IssuerNameField; + } + set { + this.x509IssuerNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string X509SerialNumber { + get { + return this.x509SerialNumberField; + } + set { + this.x509SerialNumberField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class PGPDataType { + + private byte[] pGPKeyIDField; + + private byte[] pGPKeyPacketField; + + private System.Xml.XmlElement[] anyField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] + public byte[] PGPKeyID { + get { + return this.pGPKeyIDField; + } + set { + this.pGPKeyIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] + public byte[] PGPKeyPacket { + get { + return this.pGPKeyPacketField; + } + set { + this.pGPKeyPacketField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public partial class SPKIDataType { + + private byte[][] sPKISexpField; + + private System.Xml.XmlElement anyField; + + /// + [System.Xml.Serialization.XmlElementAttribute("SPKISexp", DataType="base64Binary")] + public byte[][] SPKISexp { + get { + return this.sPKISexpField; + } + set { + this.sPKISexpField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(AttributeType))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class AttributeDesignatorType { + + private string attributeNameField; + + private string attributeNamespaceField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string AttributeName { + get { + return this.attributeNameField; + } + set { + this.attributeNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string AttributeNamespace { + get { + return this.attributeNamespaceField; + } + set { + this.attributeNamespaceField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class AttributeType : AttributeDesignatorType { + + private object[] attributeValueField; + + /// + [System.Xml.Serialization.XmlElementAttribute("AttributeValue")] + public object[] AttributeValue { + get { + return this.attributeValueField; + } + set { + this.attributeValueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class EvidenceType { + + private string[] assertionIDReferenceField; + + private AssertionType[] assertionField; + + /// + [System.Xml.Serialization.XmlElementAttribute("AssertionIDReference", DataType="NCName")] + public string[] AssertionIDReference { + get { + return this.assertionIDReferenceField; + } + set { + this.assertionIDReferenceField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("Assertion")] + public AssertionType[] Assertion { + get { + return this.assertionField; + } + set { + this.assertionField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class AssertionType { + + private ConditionsType conditionsField; + + private AdviceType adviceField; + + private StatementAbstractType[] statementField; + + private SubjectStatementAbstractType[] subjectStatementField; + + private AuthenticationStatementType[] authenticationStatementField; + + private AuthorizationDecisionStatementType[] authorizationDecisionStatementField; + + private AttributeStatementType[] attributeStatementField; + + private SignatureType signatureField; + + private string majorVersionField; + + private string minorVersionField; + + private string assertionIDField; + + private string issuerField; + + private System.DateTime issueInstantField; + + /// + public ConditionsType Conditions { + get { + return this.conditionsField; + } + set { + this.conditionsField = value; + } + } + + /// + public AdviceType Advice { + get { + return this.adviceField; + } + set { + this.adviceField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("Statement")] + public StatementAbstractType[] Statement { + get { + return this.statementField; + } + set { + this.statementField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("SubjectStatement")] + public SubjectStatementAbstractType[] SubjectStatement { + get { + return this.subjectStatementField; + } + set { + this.subjectStatementField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("AuthenticationStatement")] + public AuthenticationStatementType[] AuthenticationStatement { + get { + return this.authenticationStatementField; + } + set { + this.authenticationStatementField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("AuthorizationDecisionStatement")] + public AuthorizationDecisionStatementType[] AuthorizationDecisionStatement { + get { + return this.authorizationDecisionStatementField; + } + set { + this.authorizationDecisionStatementField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("AttributeStatement")] + public AttributeStatementType[] AttributeStatement { + get { + return this.attributeStatementField; + } + set { + this.attributeStatementField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public SignatureType Signature { + get { + return this.signatureField; + } + set { + this.signatureField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="integer")] + public string MajorVersion { + get { + return this.majorVersionField; + } + set { + this.majorVersionField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="integer")] + public string MinorVersion { + get { + return this.minorVersionField; + } + set { + this.minorVersionField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="ID")] + public string AssertionID { + get { + return this.assertionIDField; + } + set { + this.assertionIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string Issuer { + get { + return this.issuerField; + } + set { + this.issuerField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public System.DateTime IssueInstant { + get { + return this.issueInstantField; + } + set { + this.issueInstantField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class ConditionsType { + + private AudienceRestrictionConditionType[] audienceRestrictionConditionField; + + private DoNotCacheConditionType[] doNotCacheConditionField; + + private ConditionAbstractType[] conditionField; + + private System.DateTime notBeforeField; + + private bool notBeforeFieldSpecified; + + private System.DateTime notOnOrAfterField; + + private bool notOnOrAfterFieldSpecified; + + /// + [System.Xml.Serialization.XmlElementAttribute("AudienceRestrictionCondition")] + public AudienceRestrictionConditionType[] AudienceRestrictionCondition { + get { + return this.audienceRestrictionConditionField; + } + set { + this.audienceRestrictionConditionField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("DoNotCacheCondition")] + public DoNotCacheConditionType[] DoNotCacheCondition { + get { + return this.doNotCacheConditionField; + } + set { + this.doNotCacheConditionField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("Condition")] + public ConditionAbstractType[] Condition { + get { + return this.conditionField; + } + set { + this.conditionField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public System.DateTime NotBefore { + get { + return this.notBeforeField; + } + set { + this.notBeforeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool NotBeforeSpecified { + get { + return this.notBeforeFieldSpecified; + } + set { + this.notBeforeFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public System.DateTime NotOnOrAfter { + get { + return this.notOnOrAfterField; + } + set { + this.notOnOrAfterField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool NotOnOrAfterSpecified { + get { + return this.notOnOrAfterFieldSpecified; + } + set { + this.notOnOrAfterFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class AudienceRestrictionConditionType : ConditionAbstractType { + + private string[] audienceField; + + /// + [System.Xml.Serialization.XmlElementAttribute("Audience", DataType="anyURI")] + public string[] Audience { + get { + return this.audienceField; + } + set { + this.audienceField = value; + } + } + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DoNotCacheConditionType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(AudienceRestrictionConditionType))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public abstract partial class ConditionAbstractType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class DoNotCacheConditionType : ConditionAbstractType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class AdviceType { + + private string[] assertionIDReferenceField; + + private AssertionType[] assertionField; + + private System.Xml.XmlElement anyField; + + /// + [System.Xml.Serialization.XmlElementAttribute("AssertionIDReference", DataType="NCName")] + public string[] AssertionIDReference { + get { + return this.assertionIDReferenceField; + } + set { + this.assertionIDReferenceField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("Assertion")] + public AssertionType[] Assertion { + get { + return this.assertionField; + } + set { + this.assertionField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(SubjectStatementAbstractType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(AttributeStatementType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(AuthorizationDecisionStatementType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(AuthenticationStatementType))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public abstract partial class StatementAbstractType { + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(AttributeStatementType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(AuthorizationDecisionStatementType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(AuthenticationStatementType))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public abstract partial class SubjectStatementAbstractType : StatementAbstractType { + + private SubjectType subjectField; + + /// + public SubjectType Subject { + get { + return this.subjectField; + } + set { + this.subjectField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class SubjectType { + + private NameIdentifierType nameIdentifierField; + + private SubjectConfirmationType subjectConfirmationField; + + /// + public NameIdentifierType NameIdentifier { + get { + return this.nameIdentifierField; + } + set { + this.nameIdentifierField = value; + } + } + + /// + public SubjectConfirmationType SubjectConfirmation { + get { + return this.subjectConfirmationField; + } + set { + this.subjectConfirmationField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class NameIdentifierType { + + private string nameQualifierField; + + private string formatField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string NameQualifier { + get { + return this.nameQualifierField; + } + set { + this.nameQualifierField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string Format { + get { + return this.formatField; + } + set { + this.formatField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class SubjectConfirmationType { + + private string[] confirmationMethodField; + + private object subjectConfirmationDataField; + + private KeyInfoType keyInfoField; + + /// + [System.Xml.Serialization.XmlElementAttribute("ConfirmationMethod", DataType="anyURI")] + public string[] ConfirmationMethod { + get { + return this.confirmationMethodField; + } + set { + this.confirmationMethodField = value; + } + } + + /// + public object SubjectConfirmationData { + get { + return this.subjectConfirmationDataField; + } + set { + this.subjectConfirmationDataField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public KeyInfoType KeyInfo { + get { + return this.keyInfoField; + } + set { + this.keyInfoField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class AttributeStatementType : SubjectStatementAbstractType { + + private AttributeType[] attributeField; + + /// + [System.Xml.Serialization.XmlElementAttribute("Attribute")] + public AttributeType[] Attribute { + get { + return this.attributeField; + } + set { + this.attributeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class AuthorizationDecisionStatementType : SubjectStatementAbstractType { + + private ActionType[] actionField; + + private EvidenceType evidenceField; + + private string resourceField; + + private DecisionType decisionField; + + /// + [System.Xml.Serialization.XmlElementAttribute("Action")] + public ActionType[] Action { + get { + return this.actionField; + } + set { + this.actionField = value; + } + } + + /// + public EvidenceType Evidence { + get { + return this.evidenceField; + } + set { + this.evidenceField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string Resource { + get { + return this.resourceField; + } + set { + this.resourceField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public DecisionType Decision { + get { + return this.decisionField; + } + set { + this.decisionField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public enum DecisionType { + + /// + Permit, + + /// + Deny, + + /// + Indeterminate, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class AuthenticationStatementType : SubjectStatementAbstractType { + + private SubjectLocalityType subjectLocalityField; + + private AuthorityBindingType[] authorityBindingField; + + private string authenticationMethodField; + + private System.DateTime authenticationInstantField; + + /// + public SubjectLocalityType SubjectLocality { + get { + return this.subjectLocalityField; + } + set { + this.subjectLocalityField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute("AuthorityBinding")] + public AuthorityBindingType[] AuthorityBinding { + get { + return this.authorityBindingField; + } + set { + this.authorityBindingField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string AuthenticationMethod { + get { + return this.authenticationMethodField; + } + set { + this.authenticationMethodField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public System.DateTime AuthenticationInstant { + get { + return this.authenticationInstantField; + } + set { + this.authenticationInstantField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class SubjectLocalityType { + + private string iPAddressField; + + private string dNSAddressField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string IPAddress { + get { + return this.iPAddressField; + } + set { + this.iPAddressField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string DNSAddress { + get { + return this.dNSAddressField; + } + set { + this.dNSAddressField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public partial class AuthorityBindingType { + + private System.Xml.XmlQualifiedName authorityKindField; + + private string locationField; + + private string bindingField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public System.Xml.XmlQualifiedName AuthorityKind { + get { + return this.authorityKindField; + } + set { + this.authorityKindField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string Location { + get { + return this.locationField; + } + set { + this.locationField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string Binding { + get { + return this.bindingField; + } + set { + this.bindingField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2004/08/addressing")] + public partial class ServiceNameType { + + private string portNameField; + + private System.Xml.XmlAttribute[] anyAttrField; + + private System.Xml.XmlQualifiedName valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="NCName")] + public string PortName { + get { + return this.portNameField; + } + set { + this.portNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public System.Xml.XmlQualifiedName Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2004/08/addressing")] + public partial class AttributedQName { + + private System.Xml.XmlAttribute[] anyAttrField; + + private System.Xml.XmlQualifiedName valueField; + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public System.Xml.XmlQualifiedName Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(TypeName="ReferenceParametersType", Namespace="http://schemas.xmlsoap.org/ws/2004/08/addressing")] + public partial class ReferenceParametersType1 { + + private System.Xml.XmlElement[] anyField; + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2004/08/addressing")] + public partial class ReferencePropertiesType { + + private System.Xml.XmlElement[] anyField; + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(TypeName="EndpointReferenceType", Namespace="http://schemas.xmlsoap.org/ws/2004/08/addressing")] + public partial class EndpointReferenceType1 { + + private AttributedURI addressField; + + private ReferencePropertiesType referencePropertiesField; + + private ReferenceParametersType1 referenceParametersField; + + private AttributedQName portTypeField; + + private ServiceNameType serviceNameField; + + private System.Xml.XmlElement[] anyField; + + private System.Xml.XmlAttribute[] anyAttrField; + + /// + public AttributedURI Address { + get { + return this.addressField; + } + set { + this.addressField = value; + } + } + + /// + public ReferencePropertiesType ReferenceProperties { + get { + return this.referencePropertiesField; + } + set { + this.referencePropertiesField = value; + } + } + + /// + public ReferenceParametersType1 ReferenceParameters { + get { + return this.referenceParametersField; + } + set { + this.referenceParametersField = value; + } + } + + /// + public AttributedQName PortType { + get { + return this.portTypeField; + } + set { + this.portTypeField = value; + } + } + + /// + public ServiceNameType ServiceName { + get { + return this.serviceNameField; + } + set { + this.serviceNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2004/08/addressing")] + [System.Xml.Serialization.XmlRootAttribute("Action", Namespace="http://schemas.xmlsoap.org/ws/2004/08/addressing", IsNullable=false)] + public partial class AttributedURI : System.Web.Services.Protocols.SoapHeader { + + private System.Xml.XmlAttribute[] anyAttrField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType="anyURI")] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2005/08/addressing")] + public partial class ProblemActionType { + + private Action actionField; + + private string soapActionField; + + private System.Xml.XmlAttribute[] anyAttrField; + + /// + public Action Action { + get { + return this.actionField; + } + set { + this.actionField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="anyURI")] + public string SoapAction { + get { + return this.soapActionField; + } + set { + this.soapActionField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.w3.org/2005/08/addressing")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.w3.org/2005/08/addressing", IsNullable=false)] + public partial class Action : AttributedURIType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2005/08/addressing")] + [System.Xml.Serialization.XmlRootAttribute("MessageID", Namespace="http://www.w3.org/2005/08/addressing", IsNullable=false)] + public partial class AttributedURIType : System.Web.Services.Protocols.SoapHeader { + + private System.Xml.XmlAttribute[] anyAttrField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType="anyURI")] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.microsoft.com/Passport/SoapServices/SOAPFault")] + public partial class errorType { + + private uint valueField; + + private internalerrorType internalerrorField; + + /// + public uint value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + + /// + public internalerrorType internalerror { + get { + return this.internalerrorField; + } + set { + this.internalerrorField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.microsoft.com/Passport/SoapServices/SOAPFault")] + public partial class internalerrorType { + + private uint codeField; + + private bool codeFieldSpecified; + + private string textField; + + /// + public uint code { + get { + return this.codeField; + } + set { + this.codeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool codeSpecified { + get { + return this.codeFieldSpecified; + } + set { + this.codeFieldSpecified = value; + } + } + + /// + public string text { + get { + return this.textField; + } + set { + this.textField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.microsoft.com/Passport/SoapServices/SOAPFault")] + public partial class extPropertyType { + + private bool ignoreRememberMeField; + + private bool ignoreRememberMeFieldSpecified; + + private string domainsField; + + private string expiryField; + + private string nameField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public bool IgnoreRememberMe { + get { + return this.ignoreRememberMeField; + } + set { + this.ignoreRememberMeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool IgnoreRememberMeSpecified { + get { + return this.ignoreRememberMeFieldSpecified; + } + set { + this.ignoreRememberMeFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string Domains { + get { + return this.domainsField; + } + set { + this.domainsField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string Expiry { + get { + return this.expiryField; + } + set { + this.expiryField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.microsoft.com/Passport/SoapServices/SOAPFault")] + public partial class credPropertyType { + + private string nameField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.microsoft.com/Passport/SoapServices/SOAPFault")] + public partial class browserCookieType { + + private string nameField; + + private string uRLField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="anyURI")] + public string URL { + get { + return this.uRLField; + } + set { + this.uRLField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.microsoft.com/Passport/SoapServices/SOAPFault")] + public partial class serverInfoType { + + private System.DateTime serverTimeField; + + private bool serverTimeFieldSpecified; + + private string locVersionField; + + private string rollingUpgradeStateField; + + private string pathField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public System.DateTime ServerTime { + get { + return this.serverTimeField; + } + set { + this.serverTimeField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ServerTimeSpecified { + get { + return this.serverTimeFieldSpecified; + } + set { + this.serverTimeFieldSpecified = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="integer")] + public string LocVersion { + get { + return this.locVersionField; + } + set { + this.locVersionField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string RollingUpgradeState { + get { + return this.rollingUpgradeStateField; + } + set { + this.rollingUpgradeStateField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string Path { + get { + return this.pathField; + } + set { + this.pathField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] + public partial class BinarySecretType { + + private string valueField; + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] + public partial class RequestedProofTokenType { + + private BinarySecretType binarySecretField; + + /// + public BinarySecretType BinarySecret { + get { + return this.binarySecretField; + } + set { + this.binarySecretField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] + public partial class RequestedTokenReferenceType { + + private KeyIdentifierType keyIdentifierField; + + private ReferenceType referenceField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" + + "")] + public KeyIdentifierType KeyIdentifier { + get { + return this.keyIdentifierField; + } + set { + this.keyIdentifierField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" + + "")] + public ReferenceType Reference { + get { + return this.referenceField; + } + set { + this.referenceField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" + + "")] + public partial class KeyIdentifierType : EncodedString { + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(BinarySecurityTokenType))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(KeyIdentifierType))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" + + "")] + public partial class EncodedString : AttributedString { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" + + "")] + public partial class BinarySecurityTokenType : EncodedString { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] + public partial class CipherDataType { + + private string cipherValueField; + + /// + public string CipherValue { + get { + return this.cipherValueField; + } + set { + this.cipherValueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] + public partial class EncryptionMethodType { + + private string algorithmField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string Algorithm { + get { + return this.algorithmField; + } + set { + this.algorithmField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] + public partial class EncryptedDataType { + + private EncryptionMethodType encryptionMethodField; + + private KeyInfoType keyInfoField; + + private CipherDataType cipherDataField; + + private string idField; + + private string typeField; + + /// + public EncryptionMethodType EncryptionMethod { + get { + return this.encryptionMethodField; + } + set { + this.encryptionMethodField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://www.w3.org/2000/09/xmldsig#")] + public KeyInfoType KeyInfo { + get { + return this.keyInfoField; + } + set { + this.keyInfoField = value; + } + } + + /// + public CipherDataType CipherData { + get { + return this.cipherDataField; + } + set { + this.cipherDataField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string Type { + get { + return this.typeField; + } + set { + this.typeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] + public partial class RequestedSecurityTokenType { + + private System.Xml.XmlElement anyField; + + private EncryptedDataType encryptedDataField; + + private BinarySecurityTokenType binarySecurityTokenField; + + private AssertionType assertionField; + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + public EncryptedDataType EncryptedData { + get { + return this.encryptedDataField; + } + set { + this.encryptedDataField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" + + "")] + public BinarySecurityTokenType BinarySecurityToken { + get { + return this.binarySecurityTokenField; + } + set { + this.binarySecurityTokenField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:oasis:names:tc:SAML:1.0:assertion")] + public AssertionType Assertion { + get { + return this.assertionField; + } + set { + this.assertionField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] + public partial class LifetimeType { + + private AttributedDateTime createdField; + + private AttributedDateTime expiresField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xs" + + "d")] + public AttributedDateTime Created { + get { + return this.createdField; + } + set { + this.createdField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xs" + + "d")] + public AttributedDateTime Expires { + get { + return this.expiresField; + } + set { + this.expiresField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xs" + + "d")] + public partial class AttributedDateTime { + + private string idField; + + private System.Xml.XmlAttribute[] anyAttrField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="ID")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute()] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] + public partial class RequestSecurityTokenResponseType { + + private string tokenTypeField; + + private AppliesTo appliesToField; + + private LifetimeType lifetimeField; + + private RequestedSecurityTokenType requestedSecurityTokenField; + + private RequestedAttachedReference requestedAttachedReferenceField; + + private RequestedUnattachedReference requestedUnattachedReferenceField; + + private RequestedTokenReferenceType requestedTokenReferenceField; + + private RequestedProofTokenType requestedProofTokenField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="anyURI")] + public string TokenType { + get { + return this.tokenTypeField; + } + set { + this.tokenTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://schemas.xmlsoap.org/ws/2004/09/policy")] + public AppliesTo AppliesTo { + get { + return this.appliesToField; + } + set { + this.appliesToField = value; + } + } + + /// + public LifetimeType Lifetime { + get { + return this.lifetimeField; + } + set { + this.lifetimeField = value; + } + } + + /// + public RequestedSecurityTokenType RequestedSecurityToken { + get { + return this.requestedSecurityTokenField; + } + set { + this.requestedSecurityTokenField = value; + } + } + + /// + public RequestedAttachedReference RequestedAttachedReference { + get { + return this.requestedAttachedReferenceField; + } + set { + this.requestedAttachedReferenceField = value; + } + } + + /// + public RequestedUnattachedReference RequestedUnattachedReference { + get { + return this.requestedUnattachedReferenceField; + } + set { + this.requestedUnattachedReferenceField = value; + } + } + + /// + public RequestedTokenReferenceType RequestedTokenReference { + get { + return this.requestedTokenReferenceField; + } + set { + this.requestedTokenReferenceField = value; + } + } + + /// + public RequestedProofTokenType RequestedProofToken { + get { + return this.requestedProofTokenField; + } + set { + this.requestedProofTokenField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://schemas.xmlsoap.org/ws/2004/09/policy")] + public partial class AppliesTo { + + private EndpointReferenceType endpointReferenceField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://www.w3.org/2005/08/addressing")] + public EndpointReferenceType EndpointReference { + get { + return this.endpointReferenceField; + } + set { + this.endpointReferenceField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2005/08/addressing")] + public partial class EndpointReferenceType { + + private AttributedURIType addressField; + + private ReferenceParametersType referenceParametersField; + + private MetadataType metadataField; + + private System.Xml.XmlElement[] anyField; + + private System.Xml.XmlAttribute[] anyAttrField; + + /// + public AttributedURIType Address { + get { + return this.addressField; + } + set { + this.addressField = value; + } + } + + /// + public ReferenceParametersType ReferenceParameters { + get { + return this.referenceParametersField; + } + set { + this.referenceParametersField = value; + } + } + + /// + public MetadataType Metadata { + get { + return this.metadataField; + } + set { + this.metadataField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2005/08/addressing")] + public partial class ReferenceParametersType { + + private System.Xml.XmlElement[] anyField; + + private System.Xml.XmlAttribute[] anyAttrField; + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2005/08/addressing")] + public partial class MetadataType { + + private System.Xml.XmlElement[] anyField; + + private System.Xml.XmlAttribute[] anyAttrField; + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] + public partial class RequestedAttachedReference { + + private SecurityTokenReferenceType securityTokenReferenceField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" + + "")] + public SecurityTokenReferenceType SecurityTokenReference { + get { + return this.securityTokenReferenceField; + } + set { + this.securityTokenReferenceField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] + public partial class RequestedUnattachedReference { + + private SecurityTokenReferenceType securityTokenReferenceField; + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" + + "")] + public SecurityTokenReferenceType SecurityTokenReference { + get { + return this.securityTokenReferenceField; + } + set { + this.securityTokenReferenceField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] + public partial class RequestSecurityTokenType { + + private string tokenTypeField; + + private RequestTypeOpenEnum requestTypeField; + + private AppliesTo appliesToField; + + private PolicyReference policyReferenceField; + + private System.Xml.XmlElement[] anyField; + + private string idField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="anyURI")] + public string TokenType { + get { + return this.tokenTypeField; + } + set { + this.tokenTypeField = value; + } + } + + /// + public RequestTypeOpenEnum RequestType { + get { + return this.requestTypeField; + } + set { + this.requestTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://schemas.xmlsoap.org/ws/2004/09/policy")] + public AppliesTo AppliesTo { + get { + return this.appliesToField; + } + set { + this.appliesToField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(Namespace="http://schemas.xmlsoap.org/ws/2004/09/policy")] + public PolicyReference PolicyReference { + get { + return this.policyReferenceField; + } + set { + this.policyReferenceField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement[] Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] + public enum RequestTypeOpenEnum { + + /// + [System.Xml.Serialization.XmlEnumAttribute("http://schemas.xmlsoap.org/ws/2005/02/trust/Issue")] + httpschemasxmlsoaporgws200502trustIssue, + + /// + [System.Xml.Serialization.XmlEnumAttribute("http://schemas.xmlsoap.org/ws/2005/02/trust/Renew")] + httpschemasxmlsoaporgws200502trustRenew, + + /// + [System.Xml.Serialization.XmlEnumAttribute("http://schemas.xmlsoap.org/ws/2005/02/trust/Cancel")] + httpschemasxmlsoaporgws200502trustCancel, + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://schemas.xmlsoap.org/ws/2004/09/policy")] + public partial class PolicyReference { + + private string uRIField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string URI { + get { + return this.uRIField; + } + set { + this.uRIField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.microsoft.com/Passport/SoapServices/PPCRL")] + public partial class RequestMultipleSecurityTokensType { + + private RequestSecurityTokenType[] requestSecurityTokenField; + + private string idField; + + /// + [System.Xml.Serialization.XmlElementAttribute("RequestSecurityToken", Namespace="http://schemas.xmlsoap.org/ws/2005/02/trust")] + public RequestSecurityTokenType[] RequestSecurityToken { + get { + return this.requestSecurityTokenField; + } + set { + this.requestSecurityTokenField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xs" + + "d")] + public partial class TimestampType { + + private AttributedDateTime createdField; + + private AttributedDateTime expiresField; + + private System.Xml.XmlElement anyField; + + private string idField; + + private System.Xml.XmlAttribute[] anyAttrField; + + /// + public AttributedDateTime Created { + get { + return this.createdField; + } + set { + this.createdField = value; + } + } + + /// + public AttributedDateTime Expires { + get { + return this.expiresField; + } + set { + this.expiresField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyElementAttribute()] + public System.Xml.XmlElement Any { + get { + return this.anyField; + } + set { + this.anyField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute(DataType="ID")] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" + + "")] + public partial class PasswordString : AttributedString { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.xmlsoap.org/ws/2004/08/addressing")] + [System.Xml.Serialization.XmlRootAttribute("RelatesTo", Namespace="http://schemas.xmlsoap.org/ws/2004/08/addressing", IsNullable=false)] + public partial class Relationship : System.Web.Services.Protocols.SoapHeader { + + private System.Xml.XmlQualifiedName relationshipTypeField; + + private System.Xml.XmlAttribute[] anyAttrField; + + private string valueField; + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public System.Xml.XmlQualifiedName RelationshipType { + get { + return this.relationshipTypeField; + } + set { + this.relationshipTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType="anyURI")] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.w3.org/2005/08/addressing")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.w3.org/2005/08/addressing", IsNullable=false)] + public partial class To : AttributedURIType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.microsoft.com/Passport/SoapServices/SOAPFault")] + [System.Xml.Serialization.XmlRootAttribute("pp", Namespace="http://schemas.microsoft.com/Passport/SoapServices/SOAPFault", IsNullable=false)] + public partial class ppHeaderType : System.Web.Services.Protocols.SoapHeader { + + private string serverVersionField; + + private string pUIDField; + + private string configVersionField; + + private string uiVersionField; + + private string authstateField; + + private string reqstatusField; + + private serverInfoType serverInfoField; + + private object cookiesField; + + private browserCookieType[] browserCookiesField; + + private credPropertyType[] credPropertiesField; + + private extPropertyType[] extPropertiesField; + + private object responseField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="integer")] + public string serverVersion { + get { + return this.serverVersionField; + } + set { + this.serverVersionField = value; + } + } + + /// + public string PUID { + get { + return this.pUIDField; + } + set { + this.pUIDField = value; + } + } + + /// + public string configVersion { + get { + return this.configVersionField; + } + set { + this.configVersionField = value; + } + } + + /// + public string uiVersion { + get { + return this.uiVersionField; + } + set { + this.uiVersionField = value; + } + } + + /// + public string authstate { + get { + return this.authstateField; + } + set { + this.authstateField = value; + } + } + + /// + public string reqstatus { + get { + return this.reqstatusField; + } + set { + this.reqstatusField = value; + } + } + + /// + public serverInfoType serverInfo { + get { + return this.serverInfoField; + } + set { + this.serverInfoField = value; + } + } + + /// + public object cookies { + get { + return this.cookiesField; + } + set { + this.cookiesField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("browserCookie", IsNullable=false)] + public browserCookieType[] browserCookies { + get { + return this.browserCookiesField; + } + set { + this.browserCookiesField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("credProperty", IsNullable=false)] + public credPropertyType[] credProperties { + get { + return this.credPropertiesField; + } + set { + this.credPropertiesField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("extProperty", IsNullable=false)] + public extPropertyType[] extProperties { + get { + return this.extPropertiesField; + } + set { + this.extPropertiesField = value; + } + } + + /// + public object response { + get { + return this.responseField; + } + set { + this.responseField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.w3.org/2005/08/addressing")] + [System.Xml.Serialization.XmlRootAttribute("RelatesTo", Namespace="http://www.w3.org/2005/08/addressing", IsNullable=false)] + public partial class RelatesToType : System.Web.Services.Protocols.SoapHeader { + + private string relationshipTypeField; + + private System.Xml.XmlAttribute[] anyAttrField; + + private string valueField; + + public RelatesToType() { + this.relationshipTypeField = "http://www.w3.org/2005/08/addressing/reply"; + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + [System.ComponentModel.DefaultValueAttribute("http://www.w3.org/2005/08/addressing/reply")] + public string RelationshipType { + get { + return this.relationshipTypeField; + } + set { + this.relationshipTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlAnyAttributeAttribute()] + public System.Xml.XmlAttribute[] AnyAttr { + get { + return this.anyAttrField; + } + set { + this.anyAttrField = value; + } + } + + /// + [System.Xml.Serialization.XmlTextAttribute(DataType="anyURI")] + public string Value { + get { + return this.valueField; + } + set { + this.valueField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.microsoft.com/Passport/SoapServices/PPCRL")] + [System.Xml.Serialization.XmlRootAttribute("AuthInfo", Namespace="http://schemas.microsoft.com/Passport/SoapServices/PPCRL", IsNullable=false)] + public partial class AuthInfoType : System.Web.Services.Protocols.SoapHeader { + + private string hostingAppField; + + private string binaryVersionField; + + private string uIVersionField; + + private string cookiesField; + + private string requestParamsField; + + private string idField; + + public AuthInfoType() { + this.hostingAppField = "{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}"; + this.binaryVersionField = "5"; + this.uIVersionField = "1"; + this.requestParamsField = "AQAAAAIAAABsYwQAAAAyMDUy"; + } + + /// + public string HostingApp { + get { + return this.hostingAppField; + } + set { + this.hostingAppField = value; + } + } + + /// + public string BinaryVersion { + get { + return this.binaryVersionField; + } + set { + this.binaryVersionField = value; + } + } + + /// + public string UIVersion { + get { + return this.uIVersionField; + } + set { + this.uIVersionField = value; + } + } + + /// + public string Cookies { + get { + return this.cookiesField; + } + set { + this.cookiesField = value; + } + } + + /// + public string RequestParams { + get { + return this.requestParamsField; + } + set { + this.requestParamsField = value; + } + } + + /// + [System.Xml.Serialization.XmlAttributeAttribute()] + public string Id { + get { + return this.idField; + } + set { + this.idField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void RequestMultipleSecurityTokensCompletedEventHandler(object sender, RequestMultipleSecurityTokensCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class RequestMultipleSecurityTokensCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal RequestMultipleSecurityTokensCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public RequestSecurityTokenResponseType[] Result { + get { + this.RaiseExceptionIfNecessary(); + return ((RequestSecurityTokenResponseType[])(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void RequestSecurityTokenCompletedEventHandler(object sender, RequestSecurityTokenCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class RequestSecurityTokenCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal RequestSecurityTokenCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public RequestSecurityTokenResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((RequestSecurityTokenResponseType)(this.results[0])); + } + } + } +} + +#pragma warning restore 1591 \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/Reference.map b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/Reference.map new file mode 100644 index 0000000..2a58f5a --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/Reference.map @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/RequestSecurityTokenResponseType.datasource b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/RequestSecurityTokenResponseType.datasource new file mode 100644 index 0000000..a1fa012 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/RequestSecurityTokenResponseType.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNSecurityTokenService.RequestSecurityTokenResponseType, Web References.MSNWS.MSNSecurityTokenService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/addressing-04-08.xsd b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/addressing-04-08.xsd new file mode 100644 index 0000000..b48c1f8 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/addressing-04-08.xsd @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + If "Policy" elements from namespace "http://schemas.xmlsoap.org/ws/2002/12/policy#policy" are used, they must appear first (before any extensibility elements). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/addressing.xsd b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/addressing.xsd new file mode 100644 index 0000000..58ab38c --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/addressing.xsd @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ps-fault.xsd b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ps-fault.xsd new file mode 100644 index 0000000..f3950d4 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ps-fault.xsd @@ -0,0 +1,119 @@ + + + + + Comment describing your root element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ps.wsdl b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ps.wsdl new file mode 100644 index 0000000..b01ed49 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ps.wsdl @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ps.xsd b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ps.xsd new file mode 100644 index 0000000..ef39825 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ps.xsd @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/soap-env-03-05.xsd b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/soap-env-03-05.xsd new file mode 100644 index 0000000..34f2d30 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/soap-env-03-05.xsd @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + Elements replacing the wildcard MUST be namespace qualified, but can be in the targetNamespace + + + + + + + + + + + + + + + + + + + + + + + Fault reporting structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/soap-env.xsd b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/soap-env.xsd new file mode 100644 index 0000000..83c67dc --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/soap-env.xsd @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Prose in the spec does not specify that attributes are allowed on the Body element + + + + + + + + + + + + + + + + 'encodingStyle' indicates any canonicalization conventions followed in the contents of the containing element. For example, the value 'http://schemas.xmlsoap.org/soap/encoding/' indicates the pattern described in SOAP specification + + + + + + + + + + + + + Fault reporting structure + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/sstc-saml-schema-assertion-1.xsd b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/sstc-saml-schema-assertion-1.xsd new file mode 100644 index 0000000..09f88fe --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/sstc-saml-schema-assertion-1.xsd @@ -0,0 +1,200 @@ + + + + + + Document identifier: sstc-saml-schema-assertion-1.1-cs + Location: http://www.oasis-open.org/committees/documents.php?wg_abbrev=security + Revision history: + V1.0 (November, 2002): + Initial standard schema. + V1.1 (May, 2003): + * Note that V1.1 of this schema has the same XML namespace as V1.0. + Rebased ID content directly on XML Schema types + Added DoNotCacheCondition element and DoNotCacheConditionType + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ws-policy.xsd b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ws-policy.xsd new file mode 100644 index 0000000..39b551e --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ws-policy.xsd @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ws-secext.xsd b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ws-secext.xsd new file mode 100644 index 0000000..be953f6 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ws-secext.xsd @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This element defines a security token reference + + + + + This type represents a reference to an external security token. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ws-secureconversation.xsd b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ws-secureconversation.xsd new file mode 100644 index 0000000..7262b19 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ws-secureconversation.xsd @@ -0,0 +1,60 @@ + + + + + + + + + Actual content model is non-deterministic, hence wildcard. The following shows intended content model: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ws-trust.xsd b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ws-trust.xsd new file mode 100644 index 0000000..cf83451 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/ws-trust.xsd @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/wss-utility.xsd b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/wss-utility.xsd new file mode 100644 index 0000000..131a30a --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/wss-utility.xsd @@ -0,0 +1,90 @@ + + + + + +This type defines the fault code value for Timestamp message expiration. + + + + + + + + + +This global attribute supports annotating arbitrary elements with an ID. + + + + + + +Convenience attribute group used to simplify this schema. + + + + + + + + +This type is for elements whose [children] is a psuedo-dateTime and can have arbitrary attributes. + + + + + + + + + + + +This type is for elements whose [children] is an anyURI and can have arbitrary attributes. + + + + + + + + + + + +This complex type ties together the timestamp related elements into a composite type. + + + + + + + + + + + + + + +This element allows Timestamps to be applied anywhere element wildcards are present, +including as a SOAP header. + + + + + + +This element allows an expiration time to be applied anywhere element wildcards are present. + + + + + + +This element allows a creation time to be applied anywhere element wildcards are present. + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/xenc-schema.xsd b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/xenc-schema.xsd new file mode 100644 index 0000000..fff5a47 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/xenc-schema.xsd @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/xml.xsd b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/xml.xsd new file mode 100644 index 0000000..be134de --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/xml.xsd @@ -0,0 +1,270 @@ + + + + +
+

About the XML namespace

+
+

+ This schema document describes the XML namespace, in a form + suitable for import by other schema documents. +

+

+ See + http://www.w3.org/XML/1998/namespace.html and + + http://www.w3.org/TR/REC-xml for information + about this namespace. +

+

+ Note that local names in this namespace are intended to be + defined only by the World Wide Web Consortium or its subgroups. + The names currently defined in this namespace are listed below. + They should not be used with conflicting semantics by any Working + Group, specification, or document instance. +

+

+ See further below in this document for more information about how to refer to this schema document from your own + XSD schema documents and about the + namespace-versioning policy governing this schema document. +

+
+
+
+
+ + + +
+

lang (as an attribute name)

+

+ denotes an attribute whose value + is a language code for the natural language of the content of + any element; its value is inherited. This name is reserved + by virtue of its definition in the XML specification.

+
+
+

Notes

+

+ Attempting to install the relevant ISO 2- and 3-letter + codes as the enumerated possible values is probably never + going to be a realistic possibility. +

+

+ See BCP 47 at + http://www.rfc-editor.org/rfc/bcp/bcp47.txt + and the IANA language subtag registry at + + http://www.iana.org/assignments/language-subtag-registry + for further information. +

+

+ The union allows for the 'un-declaration' of xml:lang with + the empty string. +

+
+
+
+ + + + + + + + + +
+ + + +
+

space (as an attribute name)

+

+ denotes an attribute whose + value is a keyword indicating what whitespace processing + discipline is intended for the content of the element; its + value is inherited. This name is reserved by virtue of its + definition in the XML specification.

+
+
+
+ + + + + + +
+ + + +
+

base (as an attribute name)

+

+ denotes an attribute whose value + provides a URI to be used as the base for interpreting any + relative URIs in the scope of the element on which it + appears; its value is inherited. This name is reserved + by virtue of its definition in the XML Base specification.

+

+ See http://www.w3.org/TR/xmlbase/ + for information about this attribute. +

+
+
+
+
+ + + +
+

id (as an attribute name)

+

+ denotes an attribute whose value + should be interpreted as if declared to be of type ID. + This name is reserved by virtue of its definition in the + xml:id specification.

+

+ See http://www.w3.org/TR/xml-id/ + for information about this attribute. +

+
+
+
+
+ + + + + + + + +
+

Father (in any context at all)

+
+

+ denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and + XML Coordination groups: +

+
+

+ In appreciation for his vision, leadership and + dedication the W3C XML Plenary on this 10th day of + February, 2000, reserves for Jon Bosak in perpetuity + the XML name "xml:Father". +

+
+
+
+
+
+ + +
+

+ About this schema document +

+
+

+ This schema defines attributes and an attribute group suitable + for use by schemas wishing to allow xml:base, + xml:lang, xml:space or + xml:id attributes on elements they define. +

+

+ To enable this, such a schema must import this schema for + the XML namespace, e.g. as follows: +

+
+          <schema . . .>
+           . . .
+           <import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+     
+

+ or +

+
+           <import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
+     
+

+ Subsequently, qualified reference to any of the attributes or the + group defined below will have the desired effect, e.g. +

+
+          <type . . .>
+           . . .
+           <attributeGroup ref="xml:specialAttrs"/>
+     
+

+ will define a type which will schema-validate an instance element + with any of those attributes. +

+
+
+
+
+ + +
+

+ Versioning policy for this schema document +

+
+

+ In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + + http://www.w3.org/2009/01/xml.xsd. +

+

+ At the date of issue it can also be found at + + http://www.w3.org/2001/xml.xsd. +

+

+ The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML + Schema itself, or with the XML namespace itself. In other words, + if the XML Schema or XML namespaces change, the version of this + document at + http://www.w3.org/2001/xml.xsd + + will change accordingly; the version at + + http://www.w3.org/2009/01/xml.xsd + + will not change. +

+

+ Previous dated (and unchanging) versions of this schema + document are at: +

+ +
+
+
+
+
\ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/xmldsig-core-schema.xsd b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/xmldsig-core-schema.xsd new file mode 100644 index 0000000..3cbf611 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNSecurityTokenService/xmldsig-core-schema.xsd @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNStorageService/CreateDocumentResponseType.datasource b/MSNPSharp/Web References/MSNWS.MSNStorageService/CreateDocumentResponseType.datasource new file mode 100644 index 0000000..a598062 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNStorageService/CreateDocumentResponseType.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNStorageService.CreateDocumentResponseType, Web References.MSNWS.MSNStorageService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNStorageService/CreateProfileResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNStorageService/CreateProfileResponse.datasource new file mode 100644 index 0000000..2615e29 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNStorageService/CreateProfileResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNStorageService.CreateProfileResponse, Web References.MSNWS.MSNStorageService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNStorageService/FindDocumentsResultType.datasource b/MSNPSharp/Web References/MSNWS.MSNStorageService/FindDocumentsResultType.datasource new file mode 100644 index 0000000..4d8e0df --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNStorageService/FindDocumentsResultType.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNStorageService.FindDocumentsResultType, Web References.MSNWS.MSNStorageService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNStorageService/GetProfileResponse.datasource b/MSNPSharp/Web References/MSNWS.MSNStorageService/GetProfileResponse.datasource new file mode 100644 index 0000000..cf8202a --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNStorageService/GetProfileResponse.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNStorageService.GetProfileResponse, Web References.MSNWS.MSNStorageService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNStorageService/Reference.cs b/MSNPSharp/Web References/MSNWS.MSNStorageService/Reference.cs new file mode 100644 index 0000000..f2376c7 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNStorageService/Reference.cs @@ -0,0 +1,2497 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +// +// This source code was auto-generated by Microsoft.VSDesigner, Version 4.0.30319.42000. +// +#pragma warning disable 1591 + +namespace MSNPSharp.MSNWS.MSNStorageService { + using System; + using System.Web.Services; + using System.Diagnostics; + using System.Web.Services.Protocols; + using System.Xml.Serialization; + using System.ComponentModel; + + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Web.Services.WebServiceBindingAttribute(Name="StorageServiceBinding", Namespace="http://www.msn.com/webservices/storage/2008")] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(DocumentStream[]))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(Relationship[]))] + public partial class StorageService : System.Web.Services.Protocols.SoapHttpClientProtocol { + + private AffinityCacheHeader affinityCacheHeaderValueField; + + private StorageApplicationHeader storageApplicationHeaderValueField; + + private StorageUserHeader storageUserHeaderValueField; + + private System.Threading.SendOrPostCallback GetProfileOperationCompleted; + + private System.Threading.SendOrPostCallback UpdateProfileOperationCompleted; + + private System.Threading.SendOrPostCallback FindDocumentsOperationCompleted; + + private System.Threading.SendOrPostCallback CreateProfileOperationCompleted; + + private System.Threading.SendOrPostCallback ShareItemOperationCompleted; + + private System.Threading.SendOrPostCallback CreateDocumentOperationCompleted; + + private System.Threading.SendOrPostCallback UpdateDocumentOperationCompleted; + + private System.Threading.SendOrPostCallback CreateRelationshipsOperationCompleted; + + private System.Threading.SendOrPostCallback DeleteRelationshipsOperationCompleted; + + private bool useDefaultCredentialsSetExplicitly; + + /// + public StorageService() { + this.Url = "https://storage.msn.com/storageservice/SchematizedStore.asmx"; + if ((this.IsLocalFileSystemWebService(this.Url) == true)) { + this.UseDefaultCredentials = true; + this.useDefaultCredentialsSetExplicitly = false; + } + else { + this.useDefaultCredentialsSetExplicitly = true; + } + } + + public AffinityCacheHeader AffinityCacheHeaderValue { + get { + return this.affinityCacheHeaderValueField; + } + set { + this.affinityCacheHeaderValueField = value; + } + } + + public StorageApplicationHeader StorageApplicationHeaderValue { + get { + return this.storageApplicationHeaderValueField; + } + set { + this.storageApplicationHeaderValueField = value; + } + } + + public StorageUserHeader StorageUserHeaderValue { + get { + return this.storageUserHeaderValueField; + } + set { + this.storageUserHeaderValueField = value; + } + } + + public new string Url { + get { + return base.Url; + } + set { + if ((((this.IsLocalFileSystemWebService(base.Url) == true) + && (this.useDefaultCredentialsSetExplicitly == false)) + && (this.IsLocalFileSystemWebService(value) == false))) { + base.UseDefaultCredentials = false; + } + base.Url = value; + } + } + + public new bool UseDefaultCredentials { + get { + return base.UseDefaultCredentials; + } + set { + base.UseDefaultCredentials = value; + this.useDefaultCredentialsSetExplicitly = true; + } + } + + /// + public event GetProfileCompletedEventHandler GetProfileCompleted; + + /// + public event UpdateProfileCompletedEventHandler UpdateProfileCompleted; + + /// + public event FindDocumentsCompletedEventHandler FindDocumentsCompleted; + + /// + public event CreateProfileCompletedEventHandler CreateProfileCompleted; + + /// + public event ShareItemCompletedEventHandler ShareItemCompleted; + + /// + public event CreateDocumentCompletedEventHandler CreateDocumentCompleted; + + /// + public event UpdateDocumentCompletedEventHandler UpdateDocumentCompleted; + + /// + public event CreateRelationshipsCompletedEventHandler CreateRelationshipsCompleted; + + /// + public event DeleteRelationshipsCompletedEventHandler DeleteRelationshipsCompleted; + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("AffinityCacheHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageUserHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/storage/2008/GetProfile", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("GetProfileResponse", Namespace="http://www.msn.com/webservices/storage/2008")] + public GetProfileResponse GetProfile([System.Xml.Serialization.XmlElementAttribute("GetProfile", Namespace="http://www.msn.com/webservices/storage/2008")] GetProfileRequestType GetProfile1) { + object[] results = this.Invoke("GetProfile", new object[] { + GetProfile1}); + return ((GetProfileResponse)(results[0])); + } + + /// + public void GetProfileAsync(GetProfileRequestType GetProfile1) { + this.GetProfileAsync(GetProfile1, null); + } + + /// + public void GetProfileAsync(GetProfileRequestType GetProfile1, object userState) { + if ((this.GetProfileOperationCompleted == null)) { + this.GetProfileOperationCompleted = new System.Threading.SendOrPostCallback(this.OnGetProfileOperationCompleted); + } + this.InvokeAsync("GetProfile", new object[] { + GetProfile1}, this.GetProfileOperationCompleted, userState); + } + + private void OnGetProfileOperationCompleted(object arg) { + if ((this.GetProfileCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.GetProfileCompleted(this, new GetProfileCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("AffinityCacheHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageUserHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/storage/2008/UpdateProfile", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("UpdateProfileResponse", Namespace="http://www.msn.com/webservices/storage/2008")] + public object UpdateProfile([System.Xml.Serialization.XmlElementAttribute("UpdateProfile", Namespace="http://www.msn.com/webservices/storage/2008")] UpdateProfileRequestType UpdateProfile1) { + object[] results = this.Invoke("UpdateProfile", new object[] { + UpdateProfile1}); + return ((object)(results[0])); + } + + /// + public void UpdateProfileAsync(UpdateProfileRequestType UpdateProfile1) { + this.UpdateProfileAsync(UpdateProfile1, null); + } + + /// + public void UpdateProfileAsync(UpdateProfileRequestType UpdateProfile1, object userState) { + if ((this.UpdateProfileOperationCompleted == null)) { + this.UpdateProfileOperationCompleted = new System.Threading.SendOrPostCallback(this.OnUpdateProfileOperationCompleted); + } + this.InvokeAsync("UpdateProfile", new object[] { + UpdateProfile1}, this.UpdateProfileOperationCompleted, userState); + } + + private void OnUpdateProfileOperationCompleted(object arg) { + if ((this.UpdateProfileCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.UpdateProfileCompleted(this, new UpdateProfileCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("AffinityCacheHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageUserHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/storage/2008/FindDocuments", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("FindDocumentsResponse", Namespace="http://www.msn.com/webservices/storage/2008")] + public FindDocumentsResultType FindDocuments([System.Xml.Serialization.XmlElementAttribute("FindDocuments", Namespace="http://www.msn.com/webservices/storage/2008")] FindDocumentsRequestType FindDocuments1) { + object[] results = this.Invoke("FindDocuments", new object[] { + FindDocuments1}); + return ((FindDocumentsResultType)(results[0])); + } + + /// + public void FindDocumentsAsync(FindDocumentsRequestType FindDocuments1) { + this.FindDocumentsAsync(FindDocuments1, null); + } + + /// + public void FindDocumentsAsync(FindDocumentsRequestType FindDocuments1, object userState) { + if ((this.FindDocumentsOperationCompleted == null)) { + this.FindDocumentsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnFindDocumentsOperationCompleted); + } + this.InvokeAsync("FindDocuments", new object[] { + FindDocuments1}, this.FindDocumentsOperationCompleted, userState); + } + + private void OnFindDocumentsOperationCompleted(object arg) { + if ((this.FindDocumentsCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.FindDocumentsCompleted(this, new FindDocumentsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageUserHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/storage/2008/CreateProfile", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("CreateProfileResponse", Namespace="http://www.msn.com/webservices/storage/2008")] + public CreateProfileResponse CreateProfile([System.Xml.Serialization.XmlElementAttribute("CreateProfile", Namespace="http://www.msn.com/webservices/storage/2008")] CreateProfileRequestType CreateProfile1) { + object[] results = this.Invoke("CreateProfile", new object[] { + CreateProfile1}); + return ((CreateProfileResponse)(results[0])); + } + + /// + public void CreateProfileAsync(CreateProfileRequestType CreateProfile1) { + this.CreateProfileAsync(CreateProfile1, null); + } + + /// + public void CreateProfileAsync(CreateProfileRequestType CreateProfile1, object userState) { + if ((this.CreateProfileOperationCompleted == null)) { + this.CreateProfileOperationCompleted = new System.Threading.SendOrPostCallback(this.OnCreateProfileOperationCompleted); + } + this.InvokeAsync("CreateProfile", new object[] { + CreateProfile1}, this.CreateProfileOperationCompleted, userState); + } + + private void OnCreateProfileOperationCompleted(object arg) { + if ((this.CreateProfileCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.CreateProfileCompleted(this, new CreateProfileCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("AffinityCacheHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.Out)] + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageUserHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/storage/2008/ShareItem", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("ShareItemResponse", Namespace="http://www.msn.com/webservices/storage/2008")] + public ShareItemResponseType ShareItem([System.Xml.Serialization.XmlElementAttribute("ShareItem", Namespace="http://www.msn.com/webservices/storage/2008")] ShareItemRequestType ShareItem1) { + object[] results = this.Invoke("ShareItem", new object[] { + ShareItem1}); + return ((ShareItemResponseType)(results[0])); + } + + /// + public void ShareItemAsync(ShareItemRequestType ShareItem1) { + this.ShareItemAsync(ShareItem1, null); + } + + /// + public void ShareItemAsync(ShareItemRequestType ShareItem1, object userState) { + if ((this.ShareItemOperationCompleted == null)) { + this.ShareItemOperationCompleted = new System.Threading.SendOrPostCallback(this.OnShareItemOperationCompleted); + } + this.InvokeAsync("ShareItem", new object[] { + ShareItem1}, this.ShareItemOperationCompleted, userState); + } + + private void OnShareItemOperationCompleted(object arg) { + if ((this.ShareItemCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.ShareItemCompleted(this, new ShareItemCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("AffinityCacheHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageUserHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/storage/2008/CreateDocument", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("CreateDocumentResponse", Namespace="http://www.msn.com/webservices/storage/2008")] + public CreateDocumentResponseType CreateDocument([System.Xml.Serialization.XmlElementAttribute("CreateDocument", Namespace="http://www.msn.com/webservices/storage/2008")] CreateDocumentRequestType CreateDocument1) { + object[] results = this.Invoke("CreateDocument", new object[] { + CreateDocument1}); + return ((CreateDocumentResponseType)(results[0])); + } + + /// + public void CreateDocumentAsync(CreateDocumentRequestType CreateDocument1) { + this.CreateDocumentAsync(CreateDocument1, null); + } + + /// + public void CreateDocumentAsync(CreateDocumentRequestType CreateDocument1, object userState) { + if ((this.CreateDocumentOperationCompleted == null)) { + this.CreateDocumentOperationCompleted = new System.Threading.SendOrPostCallback(this.OnCreateDocumentOperationCompleted); + } + this.InvokeAsync("CreateDocument", new object[] { + CreateDocument1}, this.CreateDocumentOperationCompleted, userState); + } + + private void OnCreateDocumentOperationCompleted(object arg) { + if ((this.CreateDocumentCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.CreateDocumentCompleted(this, new CreateDocumentCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("AffinityCacheHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageUserHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/storage/2008/UpdateDocument", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("UpdateDocumentResponse", Namespace="http://www.msn.com/webservices/storage/2008")] + public object UpdateDocument([System.Xml.Serialization.XmlElementAttribute("UpdateDocument", Namespace="http://www.msn.com/webservices/storage/2008")] UpdateDocumentRequestType UpdateDocument1) { + object[] results = this.Invoke("UpdateDocument", new object[] { + UpdateDocument1}); + return ((object)(results[0])); + } + + /// + public void UpdateDocumentAsync(UpdateDocumentRequestType UpdateDocument1) { + this.UpdateDocumentAsync(UpdateDocument1, null); + } + + /// + public void UpdateDocumentAsync(UpdateDocumentRequestType UpdateDocument1, object userState) { + if ((this.UpdateDocumentOperationCompleted == null)) { + this.UpdateDocumentOperationCompleted = new System.Threading.SendOrPostCallback(this.OnUpdateDocumentOperationCompleted); + } + this.InvokeAsync("UpdateDocument", new object[] { + UpdateDocument1}, this.UpdateDocumentOperationCompleted, userState); + } + + private void OnUpdateDocumentOperationCompleted(object arg) { + if ((this.UpdateDocumentCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.UpdateDocumentCompleted(this, new UpdateDocumentCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("AffinityCacheHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageUserHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/storage/2008/CreateRelationships", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("CreateRelationshipsResponse", Namespace="http://www.msn.com/webservices/storage/2008")] + public object CreateRelationships([System.Xml.Serialization.XmlElementAttribute("CreateRelationships", Namespace="http://www.msn.com/webservices/storage/2008")] CreateRelationshipsRequestType CreateRelationships1) { + object[] results = this.Invoke("CreateRelationships", new object[] { + CreateRelationships1}); + return ((object)(results[0])); + } + + /// + public void CreateRelationshipsAsync(CreateRelationshipsRequestType CreateRelationships1) { + this.CreateRelationshipsAsync(CreateRelationships1, null); + } + + /// + public void CreateRelationshipsAsync(CreateRelationshipsRequestType CreateRelationships1, object userState) { + if ((this.CreateRelationshipsOperationCompleted == null)) { + this.CreateRelationshipsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnCreateRelationshipsOperationCompleted); + } + this.InvokeAsync("CreateRelationships", new object[] { + CreateRelationships1}, this.CreateRelationshipsOperationCompleted, userState); + } + + private void OnCreateRelationshipsOperationCompleted(object arg) { + if ((this.CreateRelationshipsCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.CreateRelationshipsCompleted(this, new CreateRelationshipsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageApplicationHeaderValue")] + [System.Web.Services.Protocols.SoapHeaderAttribute("AffinityCacheHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapHeaderAttribute("StorageUserHeaderValue", Direction=System.Web.Services.Protocols.SoapHeaderDirection.InOut)] + [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://www.msn.com/webservices/storage/2008/DeleteRelationships", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)] + [return: System.Xml.Serialization.XmlElementAttribute("DeleteRelationshipsResponse", Namespace="http://www.msn.com/webservices/storage/2008")] + public object DeleteRelationships([System.Xml.Serialization.XmlElementAttribute("DeleteRelationships", Namespace="http://www.msn.com/webservices/storage/2008")] DeleteRelationshipsRequestType DeleteRelationships1) { + object[] results = this.Invoke("DeleteRelationships", new object[] { + DeleteRelationships1}); + return ((object)(results[0])); + } + + /// + public void DeleteRelationshipsAsync(DeleteRelationshipsRequestType DeleteRelationships1) { + this.DeleteRelationshipsAsync(DeleteRelationships1, null); + } + + /// + public void DeleteRelationshipsAsync(DeleteRelationshipsRequestType DeleteRelationships1, object userState) { + if ((this.DeleteRelationshipsOperationCompleted == null)) { + this.DeleteRelationshipsOperationCompleted = new System.Threading.SendOrPostCallback(this.OnDeleteRelationshipsOperationCompleted); + } + this.InvokeAsync("DeleteRelationships", new object[] { + DeleteRelationships1}, this.DeleteRelationshipsOperationCompleted, userState); + } + + private void OnDeleteRelationshipsOperationCompleted(object arg) { + if ((this.DeleteRelationshipsCompleted != null)) { + System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); + this.DeleteRelationshipsCompleted(this, new DeleteRelationshipsCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); + } + } + + /// + public new void CancelAsync(object userState) { + base.CancelAsync(userState); + } + + private bool IsLocalFileSystemWebService(string url) { + if (((url == null) + || (url == string.Empty))) { + return false; + } + System.Uri wsUri = new System.Uri(url); + if (((wsUri.Port >= 1024) + && (string.Compare(wsUri.Host, "localHost", System.StringComparison.OrdinalIgnoreCase) == 0))) { + return true; + } + return false; + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/storage/2008")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.msn.com/webservices/storage/2008", IsNullable=false)] + public partial class StorageApplicationHeader : System.Web.Services.Protocols.SoapHeader { + + private string applicationIDField; + + private string scenarioField; + + public StorageApplicationHeader() { + this.applicationIDField = "Messenger Client 8.5"; + this.scenarioField = "Initial"; + } + + /// + public string ApplicationID { + get { + return this.applicationIDField; + } + set { + this.applicationIDField = value; + } + } + + /// + public string Scenario { + get { + return this.scenarioField; + } + set { + this.scenarioField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class DeleteRelationshipsRequestType { + + private Handle sourceHandleField; + + private Handle[] targetHandlesField; + + /// + public Handle sourceHandle { + get { + return this.sourceHandleField; + } + set { + this.sourceHandleField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("ObjectHandle", IsNullable=false)] + public Handle[] targetHandles { + get { + return this.targetHandlesField; + } + set { + this.targetHandlesField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class Handle { + + private Alias aliasField; + + private string relationshipNameField; + + private string resourceIDField; + + /// + public Alias Alias { + get { + return this.aliasField; + } + set { + this.aliasField = value; + } + } + + /// + public string RelationshipName { + get { + return this.relationshipNameField; + } + set { + this.relationshipNameField = value; + } + } + + /// + public string ResourceID { + get { + return this.resourceIDField; + } + set { + this.resourceIDField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class Alias { + + private string nameField; + + private string nameSpaceField; + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + public string NameSpace { + get { + return this.nameSpaceField; + } + set { + this.nameSpaceField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class CreateRelationshipsRequestType { + + private Relationship[] relationshipsField; + + /// + [System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)] + public Relationship[] relationships { + get { + return this.relationshipsField; + } + set { + this.relationshipsField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class Relationship { + + private string sourceIDField; + + private string sourceTypeField; + + private string targetIDField; + + private string targetTypeField; + + private string relationshipNameField; + + /// + public string SourceID { + get { + return this.sourceIDField; + } + set { + this.sourceIDField = value; + } + } + + /// + public string SourceType { + get { + return this.sourceTypeField; + } + set { + this.sourceTypeField = value; + } + } + + /// + public string TargetID { + get { + return this.targetIDField; + } + set { + this.targetIDField = value; + } + } + + /// + public string TargetType { + get { + return this.targetTypeField; + } + set { + this.targetTypeField = value; + } + } + + /// + public string RelationshipName { + get { + return this.relationshipNameField; + } + set { + this.relationshipNameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class CreateDocumentResponseType { + + private string createDocumentResultField; + + /// + public string CreateDocumentResult { + get { + return this.createDocumentResultField; + } + set { + this.createDocumentResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class CreateDocumentRequestType { + + private Handle parentHandleField; + + private documentBaseType documentField; + + private string relationshipNameField; + + /// + public Handle parentHandle { + get { + return this.parentHandleField; + } + set { + this.parentHandleField = value; + } + } + + /// + public documentBaseType document { + get { + return this.documentField; + } + set { + this.documentField = value; + } + } + + /// + public string relationshipName { + get { + return this.relationshipNameField; + } + set { + this.relationshipNameField = value; + } + } + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(Photo))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class documentBaseType { + + private string resourceIDField; + + private string nameField; + + private string itemTypeField; + + private string dateModifiedField; + + private DocumentStream[] documentStreamsField; + + /// + public string ResourceID { + get { + return this.resourceIDField; + } + set { + this.resourceIDField = value; + } + } + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + + /// + public string ItemType { + get { + return this.itemTypeField; + } + set { + this.itemTypeField = value; + } + } + + /// + public string DateModified { + get { + return this.dateModifiedField; + } + set { + this.dateModifiedField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)] + public DocumentStream[] DocumentStreams { + get { + return this.documentStreamsField; + } + set { + this.documentStreamsField = value; + } + } + } + + /// + [System.Xml.Serialization.XmlIncludeAttribute(typeof(PhotoStream))] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class DocumentStream { + + private string documentStreamNameField; + + private string mimeTypeField; + + private byte[] dataField; + + private int dataSizeField; + + private string preAuthURLField; + + private string preAuthURLPartnerField; + + private string documentStreamTypeField; + + private string writeModeField; + + private int streamVersionField; + + private byte[] sHA1HashField; + + private bool genieField; + + /// + public string DocumentStreamName { + get { + return this.documentStreamNameField; + } + set { + this.documentStreamNameField = value; + } + } + + /// + public string MimeType { + get { + return this.mimeTypeField; + } + set { + this.mimeTypeField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] + public byte[] Data { + get { + return this.dataField; + } + set { + this.dataField = value; + } + } + + /// + public int DataSize { + get { + return this.dataSizeField; + } + set { + this.dataSizeField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="anyURI")] + public string PreAuthURL { + get { + return this.preAuthURLField; + } + set { + this.preAuthURLField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="anyURI")] + public string PreAuthURLPartner { + get { + return this.preAuthURLPartnerField; + } + set { + this.preAuthURLPartnerField = value; + } + } + + /// + public string DocumentStreamType { + get { + return this.documentStreamTypeField; + } + set { + this.documentStreamTypeField = value; + } + } + + /// + public string WriteMode { + get { + return this.writeModeField; + } + set { + this.writeModeField = value; + } + } + + /// + public int StreamVersion { + get { + return this.streamVersionField; + } + set { + this.streamVersionField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] + public byte[] SHA1Hash { + get { + return this.sHA1HashField; + } + set { + this.sHA1HashField = value; + } + } + + /// + public bool Genie { + get { + return this.genieField; + } + set { + this.genieField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class PhotoStream : DocumentStream { + + private int sizeXField; + + private bool sizeXFieldSpecified; + + private int sizeYField; + + private bool sizeYFieldSpecified; + + /// + public int SizeX { + get { + return this.sizeXField; + } + set { + this.sizeXField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool SizeXSpecified { + get { + return this.sizeXFieldSpecified; + } + set { + this.sizeXFieldSpecified = value; + } + } + + /// + public int SizeY { + get { + return this.sizeYField; + } + set { + this.sizeYField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool SizeYSpecified { + get { + return this.sizeYFieldSpecified; + } + set { + this.sizeYFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class Photo : documentBaseType { + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class UpdateDocumentRequestType { + + private documentBaseType documentField; + + /// + public documentBaseType document { + get { + return this.documentField; + } + set { + this.documentField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class ShareItemResponseType { + + private string shareItemResultField; + + /// + public string ShareItemResult { + get { + return this.shareItemResultField; + } + set { + this.shareItemResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class ShareItemRequestType { + + private string resourceIDField; + + private string displayNameField; + + /// + public string resourceID { + get { + return this.resourceIDField; + } + set { + this.resourceIDField = value; + } + } + + /// + public string displayName { + get { + return this.displayNameField; + } + set { + this.displayNameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class CreateProfileRequestType { + + private CreateProfileRequestTypeProfile profileField; + + /// + public CreateProfileRequestTypeProfile profile { + get { + return this.profileField; + } + set { + this.profileField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class CreateProfileRequestTypeProfile { + + private ExpressionProfile expressionProfileField; + + /// + public ExpressionProfile ExpressionProfile { + get { + return this.expressionProfileField; + } + set { + this.expressionProfileField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class ExpressionProfile { + + private string freeTextField; + + private string displayNameField; + + private string personalStatusField; + + private int flagsField; + + private bool flagsFieldSpecified; + + private string roleDefinitionNameField; + + /// + public string FreeText { + get { + return this.freeTextField; + } + set { + this.freeTextField = value; + } + } + + /// + public string DisplayName { + get { + return this.displayNameField; + } + set { + this.displayNameField = value; + } + } + + /// + public string PersonalStatus { + get { + return this.personalStatusField; + } + set { + this.personalStatusField = value; + } + } + + /// + public int Flags { + get { + return this.flagsField; + } + set { + this.flagsField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool FlagsSpecified { + get { + return this.flagsFieldSpecified; + } + set { + this.flagsFieldSpecified = value; + } + } + + /// + public string RoleDefinitionName { + get { + return this.roleDefinitionNameField; + } + set { + this.roleDefinitionNameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class FindDocumentsResultType { + + private FindDocumentsResultTypeDocument documentField; + + /// + public FindDocumentsResultTypeDocument Document { + get { + return this.documentField; + } + set { + this.documentField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class FindDocumentsResultTypeDocument { + + private string resourceIDField; + + private string nameField; + + /// + public string ResourceID { + get { + return this.resourceIDField; + } + set { + this.resourceIDField = value; + } + } + + /// + public string Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class FindDocumentsRequestType { + + private Handle objectHandleField; + + private FindDocumentsRequestTypeDocumentAttributes documentAttributesField; + + private FindDocumentsRequestTypeDocumentFilter documentFilterField; + + private FindDocumentsRequestTypeDocumentSort documentSortField; + + private FindDocumentsRequestTypeFindContext findContextField; + + /// + public Handle objectHandle { + get { + return this.objectHandleField; + } + set { + this.objectHandleField = value; + } + } + + /// + public FindDocumentsRequestTypeDocumentAttributes documentAttributes { + get { + return this.documentAttributesField; + } + set { + this.documentAttributesField = value; + } + } + + /// + public FindDocumentsRequestTypeDocumentFilter documentFilter { + get { + return this.documentFilterField; + } + set { + this.documentFilterField = value; + } + } + + /// + public FindDocumentsRequestTypeDocumentSort documentSort { + get { + return this.documentSortField; + } + set { + this.documentSortField = value; + } + } + + /// + public FindDocumentsRequestTypeFindContext findContext { + get { + return this.findContextField; + } + set { + this.findContextField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class FindDocumentsRequestTypeDocumentAttributes { + + private bool resourceIDField; + + private bool nameField; + + /// + public bool ResourceID { + get { + return this.resourceIDField; + } + set { + this.resourceIDField = value; + } + } + + /// + public bool Name { + get { + return this.nameField; + } + set { + this.nameField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class FindDocumentsRequestTypeDocumentFilter { + + private string filterAttributesField; + + public FindDocumentsRequestTypeDocumentFilter() { + this.filterAttributesField = "None"; + } + + /// + public string FilterAttributes { + get { + return this.filterAttributesField; + } + set { + this.filterAttributesField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class FindDocumentsRequestTypeDocumentSort { + + private string sortByField; + + public FindDocumentsRequestTypeDocumentSort() { + this.sortByField = "DateModified"; + } + + /// + public string SortBy { + get { + return this.sortByField; + } + set { + this.sortByField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class FindDocumentsRequestTypeFindContext { + + private string findMethodField; + + private int chunkSizeField; + + public FindDocumentsRequestTypeFindContext() { + this.findMethodField = "Default"; + } + + /// + public string FindMethod { + get { + return this.findMethodField; + } + set { + this.findMethodField = value; + } + } + + /// + public int ChunkSize { + get { + return this.chunkSizeField; + } + set { + this.chunkSizeField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class UpdateProfileRequestType { + + private UpdateProfileRequestTypeProfile profileField; + + private UpdateProfileRequestTypeProfileAttributesToDelete profileAttributesToDeleteField; + + /// + public UpdateProfileRequestTypeProfile profile { + get { + return this.profileField; + } + set { + this.profileField = value; + } + } + + /// + public UpdateProfileRequestTypeProfileAttributesToDelete profileAttributesToDelete { + get { + return this.profileAttributesToDeleteField; + } + set { + this.profileAttributesToDeleteField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class UpdateProfileRequestTypeProfile { + + private string resourceIDField; + + private ExpressionProfile expressionProfileField; + + /// + public string ResourceID { + get { + return this.resourceIDField; + } + set { + this.resourceIDField = value; + } + } + + /// + public ExpressionProfile ExpressionProfile { + get { + return this.expressionProfileField; + } + set { + this.expressionProfileField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class UpdateProfileRequestTypeProfileAttributesToDelete { + + private ExpressionProfileAttributesType expressionProfileAttributesField; + + /// + public ExpressionProfileAttributesType ExpressionProfileAttributes { + get { + return this.expressionProfileAttributesField; + } + set { + this.expressionProfileAttributesField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class ExpressionProfileAttributesType { + + private bool resourceIDField; + + private bool resourceIDFieldSpecified; + + private bool dateModifiedField; + + private bool dateModifiedFieldSpecified; + + private bool displayNameField; + + private bool displayNameFieldSpecified; + + private bool displayNameLastModifiedField; + + private bool displayNameLastModifiedFieldSpecified; + + private bool personalStatusField; + + private bool personalStatusFieldSpecified; + + private bool personalStatusLastModifiedField; + + private bool personalStatusLastModifiedFieldSpecified; + + private bool staticUserTilePublicURLField; + + private bool staticUserTilePublicURLFieldSpecified; + + private bool photoField; + + private bool photoFieldSpecified; + + private bool attachmentsField; + + private bool attachmentsFieldSpecified; + + private bool flagField; + + private bool flagFieldSpecified; + + /// + public bool ResourceID { + get { + return this.resourceIDField; + } + set { + this.resourceIDField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool ResourceIDSpecified { + get { + return this.resourceIDFieldSpecified; + } + set { + this.resourceIDFieldSpecified = value; + } + } + + /// + public bool DateModified { + get { + return this.dateModifiedField; + } + set { + this.dateModifiedField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool DateModifiedSpecified { + get { + return this.dateModifiedFieldSpecified; + } + set { + this.dateModifiedFieldSpecified = value; + } + } + + /// + public bool DisplayName { + get { + return this.displayNameField; + } + set { + this.displayNameField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool DisplayNameSpecified { + get { + return this.displayNameFieldSpecified; + } + set { + this.displayNameFieldSpecified = value; + } + } + + /// + public bool DisplayNameLastModified { + get { + return this.displayNameLastModifiedField; + } + set { + this.displayNameLastModifiedField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool DisplayNameLastModifiedSpecified { + get { + return this.displayNameLastModifiedFieldSpecified; + } + set { + this.displayNameLastModifiedFieldSpecified = value; + } + } + + /// + public bool PersonalStatus { + get { + return this.personalStatusField; + } + set { + this.personalStatusField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PersonalStatusSpecified { + get { + return this.personalStatusFieldSpecified; + } + set { + this.personalStatusFieldSpecified = value; + } + } + + /// + public bool PersonalStatusLastModified { + get { + return this.personalStatusLastModifiedField; + } + set { + this.personalStatusLastModifiedField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PersonalStatusLastModifiedSpecified { + get { + return this.personalStatusLastModifiedFieldSpecified; + } + set { + this.personalStatusLastModifiedFieldSpecified = value; + } + } + + /// + public bool StaticUserTilePublicURL { + get { + return this.staticUserTilePublicURLField; + } + set { + this.staticUserTilePublicURLField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool StaticUserTilePublicURLSpecified { + get { + return this.staticUserTilePublicURLFieldSpecified; + } + set { + this.staticUserTilePublicURLFieldSpecified = value; + } + } + + /// + public bool Photo { + get { + return this.photoField; + } + set { + this.photoField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool PhotoSpecified { + get { + return this.photoFieldSpecified; + } + set { + this.photoFieldSpecified = value; + } + } + + /// + public bool Attachments { + get { + return this.attachmentsField; + } + set { + this.attachmentsField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool AttachmentsSpecified { + get { + return this.attachmentsFieldSpecified; + } + set { + this.attachmentsFieldSpecified = value; + } + } + + /// + public bool Flag { + get { + return this.flagField; + } + set { + this.flagField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool FlagSpecified { + get { + return this.flagFieldSpecified; + } + set { + this.flagFieldSpecified = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class GetProfileResultType { + + private string resourceIDField; + + private string dateModifiedField; + + private GetProfileResultTypeExpressionProfile expressionProfileField; + + /// + public string ResourceID { + get { + return this.resourceIDField; + } + set { + this.resourceIDField = value; + } + } + + /// + public string DateModified { + get { + return this.dateModifiedField; + } + set { + this.dateModifiedField = value; + } + } + + /// + public GetProfileResultTypeExpressionProfile ExpressionProfile { + get { + return this.expressionProfileField; + } + set { + this.expressionProfileField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class GetProfileResultTypeExpressionProfile { + + private string resourceIDField; + + private string dateModifiedField; + + private int versionField; + + private bool versionFieldSpecified; + + private int flagsField; + + private documentBaseType photoField; + + private documentBaseType[] attachmentsField; + + private string personalStatusField; + + private string personalStatusLastModifiedField; + + private string displayNameField; + + private string displayNameLastModifiedField; + + private string staticUserTilePublicURLField; + + /// + public string ResourceID { + get { + return this.resourceIDField; + } + set { + this.resourceIDField = value; + } + } + + /// + public string DateModified { + get { + return this.dateModifiedField; + } + set { + this.dateModifiedField = value; + } + } + + /// + public int Version { + get { + return this.versionField; + } + set { + this.versionField = value; + } + } + + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + public bool VersionSpecified { + get { + return this.versionFieldSpecified; + } + set { + this.versionFieldSpecified = value; + } + } + + /// + public int Flags { + get { + return this.flagsField; + } + set { + this.flagsField = value; + } + } + + /// + public documentBaseType Photo { + get { + return this.photoField; + } + set { + this.photoField = value; + } + } + + /// + [System.Xml.Serialization.XmlArrayItemAttribute("Document", IsNullable=false)] + public documentBaseType[] Attachments { + get { + return this.attachmentsField; + } + set { + this.attachmentsField = value; + } + } + + /// + public string PersonalStatus { + get { + return this.personalStatusField; + } + set { + this.personalStatusField = value; + } + } + + /// + public string PersonalStatusLastModified { + get { + return this.personalStatusLastModifiedField; + } + set { + this.personalStatusLastModifiedField = value; + } + } + + /// + public string DisplayName { + get { + return this.displayNameField; + } + set { + this.displayNameField = value; + } + } + + /// + public string DisplayNameLastModified { + get { + return this.displayNameLastModifiedField; + } + set { + this.displayNameLastModifiedField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="anyURI")] + public string StaticUserTilePublicURL { + get { + return this.staticUserTilePublicURLField; + } + set { + this.staticUserTilePublicURLField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class profileAttributes { + + private bool resourceIDField; + + private bool dateModifiedField; + + private ExpressionProfileAttributesType expressionProfileAttributesField; + + public profileAttributes() { + this.resourceIDField = true; + this.dateModifiedField = true; + } + + /// + public bool ResourceID { + get { + return this.resourceIDField; + } + set { + this.resourceIDField = value; + } + } + + /// + public bool DateModified { + get { + return this.dateModifiedField; + } + set { + this.dateModifiedField = value; + } + } + + /// + public ExpressionProfileAttributesType ExpressionProfileAttributes { + get { + return this.expressionProfileAttributesField; + } + set { + this.expressionProfileAttributesField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class GetProfileRequestType { + + private Handle profileHandleField; + + private profileAttributes profileAttributesField; + + /// + public Handle profileHandle { + get { + return this.profileHandleField; + } + set { + this.profileHandleField = value; + } + } + + /// + public profileAttributes profileAttributes { + get { + return this.profileAttributesField; + } + set { + this.profileAttributesField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/storage/2008")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.msn.com/webservices/storage/2008", IsNullable=false)] + public partial class AffinityCacheHeader : System.Web.Services.Protocols.SoapHeader { + + private string cacheKeyField; + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="token")] + public string CacheKey { + get { + return this.cacheKeyField; + } + set { + this.cacheKeyField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/storage/2008")] + [System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.msn.com/webservices/storage/2008", IsNullable=false)] + public partial class StorageUserHeader : System.Web.Services.Protocols.SoapHeader { + + private int puidField; + + private int cidField; + + private string ticketTokenField; + + private bool isAdminField; + + public StorageUserHeader() { + this.puidField = 0; + this.cidField = 0; + this.isAdminField = false; + } + + /// + public int Puid { + get { + return this.puidField; + } + set { + this.puidField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(0)] + public int Cid { + get { + return this.cidField; + } + set { + this.cidField = value; + } + } + + /// + [System.Xml.Serialization.XmlElementAttribute(DataType="token")] + public string TicketToken { + get { + return this.ticketTokenField; + } + set { + this.ticketTokenField = value; + } + } + + /// + [System.ComponentModel.DefaultValueAttribute(false)] + public bool IsAdmin { + get { + return this.isAdminField; + } + set { + this.isAdminField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class GetProfileResponse { + + private GetProfileResultType getProfileResultField; + + /// + public GetProfileResultType GetProfileResult { + get { + return this.getProfileResultField; + } + set { + this.getProfileResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.8.9032.0")] + [System.SerializableAttribute()] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.msn.com/webservices/storage/2008")] + public partial class CreateProfileResponse { + + private string createProfileResultField; + + /// + public string CreateProfileResult { + get { + return this.createProfileResultField; + } + set { + this.createProfileResultField = value; + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void GetProfileCompletedEventHandler(object sender, GetProfileCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class GetProfileCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal GetProfileCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public GetProfileResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((GetProfileResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void UpdateProfileCompletedEventHandler(object sender, UpdateProfileCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class UpdateProfileCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal UpdateProfileCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public object Result { + get { + this.RaiseExceptionIfNecessary(); + return ((object)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void FindDocumentsCompletedEventHandler(object sender, FindDocumentsCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class FindDocumentsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal FindDocumentsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public FindDocumentsResultType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((FindDocumentsResultType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void CreateProfileCompletedEventHandler(object sender, CreateProfileCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class CreateProfileCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal CreateProfileCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public CreateProfileResponse Result { + get { + this.RaiseExceptionIfNecessary(); + return ((CreateProfileResponse)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void ShareItemCompletedEventHandler(object sender, ShareItemCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class ShareItemCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal ShareItemCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public ShareItemResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((ShareItemResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void CreateDocumentCompletedEventHandler(object sender, CreateDocumentCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class CreateDocumentCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal CreateDocumentCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public CreateDocumentResponseType Result { + get { + this.RaiseExceptionIfNecessary(); + return ((CreateDocumentResponseType)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void UpdateDocumentCompletedEventHandler(object sender, UpdateDocumentCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class UpdateDocumentCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal UpdateDocumentCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public object Result { + get { + this.RaiseExceptionIfNecessary(); + return ((object)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void CreateRelationshipsCompletedEventHandler(object sender, CreateRelationshipsCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class CreateRelationshipsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal CreateRelationshipsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public object Result { + get { + this.RaiseExceptionIfNecessary(); + return ((object)(this.results[0])); + } + } + } + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + public delegate void DeleteRelationshipsCompletedEventHandler(object sender, DeleteRelationshipsCompletedEventArgs e); + + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.8.9032.0")] + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.ComponentModel.DesignerCategoryAttribute("code")] + public partial class DeleteRelationshipsCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { + + private object[] results; + + internal DeleteRelationshipsCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : + base(exception, cancelled, userState) { + this.results = results; + } + + /// + public object Result { + get { + this.RaiseExceptionIfNecessary(); + return ((object)(this.results[0])); + } + } + } +} + +#pragma warning restore 1591 \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNStorageService/Reference.map b/MSNPSharp/Web References/MSNWS.MSNStorageService/Reference.map new file mode 100644 index 0000000..4bd0a98 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNStorageService/Reference.map @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNStorageService/ShareItemResponseType.datasource b/MSNPSharp/Web References/MSNWS.MSNStorageService/ShareItemResponseType.datasource new file mode 100644 index 0000000..48bd510 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNStorageService/ShareItemResponseType.datasource @@ -0,0 +1,10 @@ + + + + MSNPSharp.MSNWS.MSNStorageService.ShareItemResponseType, Web References.MSNWS.MSNStorageService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNStorageService/msnstorage_datatypes.xsd b/MSNPSharp/Web References/MSNWS.MSNStorageService/msnstorage_datatypes.xsd new file mode 100644 index 0000000..67a0424 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNStorageService/msnstorage_datatypes.xsd @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNStorageService/msnstorage_servicetypes.xsd b/MSNPSharp/Web References/MSNWS.MSNStorageService/msnstorage_servicetypes.xsd new file mode 100644 index 0000000..fe9179a --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNStorageService/msnstorage_servicetypes.xsd @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Web References/MSNWS.MSNStorageService/msnstorage_ws.wsdl b/MSNPSharp/Web References/MSNWS.MSNStorageService/msnstorage_ws.wsdl new file mode 100644 index 0000000..7515443 --- /dev/null +++ b/MSNPSharp/Web References/MSNWS.MSNStorageService/msnstorage_ws.wsdl @@ -0,0 +1,260 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSNPSharp/Wink.cs b/MSNPSharp/Wink.cs new file mode 100644 index 0000000..dd66df1 --- /dev/null +++ b/MSNPSharp/Wink.cs @@ -0,0 +1,50 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; +using System.IO; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + [Serializable()] + public class Wink : MSNObject + { + public Wink() + : base() + { + //Type = MSNObjectType.Wink; + ObjectType = MSNObjectType.Unknown; + } + } +}; \ No newline at end of file diff --git a/MSNPSharp/app.config b/MSNPSharp/app.config new file mode 100644 index 0000000..5db03a9 --- /dev/null +++ b/MSNPSharp/app.config @@ -0,0 +1,31 @@ + + + + +
+ + + + + + https://msnmsgr.escargot.chat/OimWS/oim.asmx + + + https://msnmsgr.escargot.chat/rsi/rsi.asmx + + + https://msnmsgr.escargot.chat/RST2.srf + + + https://storage.msn.com/storageservice/SchematizedStore.asmx + + + https://contacts.msn.com/abservice/SharingService.asmx + + + + \ No newline at end of file diff --git a/MSNPSharp/enums.cs b/MSNPSharp/enums.cs new file mode 100644 index 0000000..323b22d --- /dev/null +++ b/MSNPSharp/enums.cs @@ -0,0 +1,1898 @@ +#region Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions (http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice +/* +Copyright (c) 2002-2011, Bas Geertsema, Xih Solutions +(http://www.xihsolutions.net), Thiago.Sayao, Pang Wu, Ethem Evlice. +All rights reserved. http://code.google.com/p/msnp-sharp/ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the names of Bas Geertsema or Xih Solutions nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ +#endregion + +using System; + +namespace MSNPSharp +{ + using MSNPSharp.Core; + + /// + /// Msn protocol speaking + /// + public enum MsnProtocol + { + MSNP18 = 18 + } + + /// + /// Specifies the type of proxy servers that can be used + /// + public enum ProxyType + { + /// No proxy server. + None, + /// A SOCKS4[A] proxy server. + Socks4, + /// A SOCKS5 proxy server. + Socks5 + } + + /// + /// Specifieds the type of a notification message. + /// + public enum NotificationType + { + /// + /// A message a remote contact send from a mobile device. + /// + Mobile = 0, + /// + /// A calendar reminder. + /// + Calendar = 1, + /// + /// An alert notification. + /// + Alert = 2 + } + + /// + /// Specifies the online presence state + /// + public enum PresenceStatus + { + /// + /// Unknown presence state. + /// + Unknown = 0, + /// + /// Contact is offline (or a remote contact is hidden). + /// + Offline, + /// + /// The client owner is hidden. + /// + Hidden, + /// + /// The contact is online. + /// + Online, + /// + /// The contact is away. + /// + Away, + /// + /// The contact is busy. + /// + Busy, + /// + /// The contact will be right back. + /// + BRB, + /// + /// The contact is out to lunch. + /// + Lunch, + /// + /// The contact is on the phone. + /// + Phone, + /// + /// The contact is idle. + /// + Idle + } + + /// + /// Defines why a user has (been) signed off. + /// + /// + /// OtherClient is used when this account has signed in from another location. ServerDown is used when the msn server is going down. + /// + public enum SignedOffReason + { + /// + /// None. + /// + None, + /// + /// User logged in on the other client. + /// + OtherClient, + /// + /// Server went down. + /// + ServerDown + } + + /// + /// One of the four lists used in the messenger network + /// + /// + /// + /// AllowedList - all contacts who are allowed to see your status + /// ReverseList - all contacts who have you on their contactlist + /// ForwardList - all contacts in your contactlist. You can send messages to those people + /// BlockedList - all contacts who you have blocked + /// + /// + [FlagsAttribute] + public enum MSNLists + { + /// + /// No msn list + /// + None = 0, + /// + /// All contacts in your contactlist. + /// + ForwardList = 1, + /// + /// All contacts who are allowed to see your status. + /// + AllowedList = 2, + /// + /// All contacts who you have blocked. + /// + BlockedList = 4, + /// + /// All contacts who have you on their contactlist. + /// + ReverseList = 8, + /// + /// All pending (for approval) contacts. + /// + PendingList = 16 + } + + /// + /// Defines the privacy mode of the owner of the contactlist + /// + /// AllExceptBlocked - Allow all contacts to send you messages except those on your blocked list + /// NoneButAllowed - Reject all messages except those from people on your allow list + /// + public enum PrivacyMode + { + /// + /// Unknown privacy mode. + /// + Unknown = 0, + /// + /// Allow all contacts to send you messages except those on your blocked list. + /// + AllExceptBlocked = 1, + /// + /// Reject all messages except those from people on your allow list. + /// + NoneButAllowed = 2 + } + + /// + /// Defines the way MSN handles with new contacts + /// + /// PromptOnAdd - Notify the clientprogram when a contact adds you and let the program handle the response itself + /// AutomaticAdd - When someone adds you MSN will automatically add them on your list + /// + /// + public enum NotifyPrivacy + { + /// + /// Unknown notify privacy. + /// + Unknown = 0, + /// + /// Notify the clientprogram when a contact adds you and let the program handle the response itself. + /// + PromptOnAdd = 1, + /// + /// When someone adds you MSN will automatically add them on your list. + /// + AutomaticAdd = 2 + } + + /// + /// Use the same display picture and personal message wherever I sign in. + /// + public enum RoamLiveProperty + { + /// + /// Unspecified + /// + Unspecified = 0, + + /// + /// Enabled + /// + Enabled = 1, + + /// + /// Disabled + /// + Disabled = 2 + } + + /// + /// Whether the contact list owner has Multiple Points of Presence Support (MPOP) that is owner connect from multiple places. + /// + public enum MPOP + { + /// + /// Unspecified + /// + Unspecified, + + /// + /// When the same user sign in at another place, sign the owner out. + /// + AutoLogoff, + + /// + /// When the same user sign in at another place, keep the owner sign in. + /// + KeepOnline + } + + /// + /// The functions a (remote) client supports. + /// + [Flags] + public enum ClientCapacities : long + { + #region old values + IsMobile = 0x01, + MsnExplorer8User = 0x02, + CanViewInkGIF = 0x04, + CanViewInkISF = 0x08, + CanVideoConference = 0x10, + CanMultiPacketMSG = 0x20, + IsMobileEnabled = 0x40, + IsDirectDeviceEnabled = 0x80, + IsMobileMessagingDisabled = 0x100, + IsWebClient = 0x200, + IsMobileDevice = 0x400, + IsTGWClient = 0x800, + HasMSNSpaces = 0x1000, + UsingXPMediaCenter = 0x2000, + /// + /// Activity support. + /// + CanDirectIM = 0x4000, + CanReceiveWinks = 0x8000, + CanMSNSearch = 0x10000, + CanReceiveVoiceClips = 0x40000, + CanSecureChannel = 0x80000, + CanSIP = 0x100000, + CanTunneledSip = 0x200000, + CanShareFolders = 0x400000, + PageModeMessaging = 0x800000, + SupportP2PTURN = 0x2000000, + SupportP2PUUNBootstrap = 0x4000000, + IsUsingAlias = 0x8000000, + + /// + /// MSN 6.0 + /// + CanHandleMSNC1 = 0x10000000, + /// + /// MSN 6.1 + /// + CanHandleMSNC2 = 0x20000000, + /// + /// MSN 6.2 + /// + CanHandleMSNC3 = 0x30000000, + /// + /// MSN 7.0 + /// + CanHandleMSNC4 = 0x40000000, + /// + /// MSN 7.5 + /// + CanHandleMSNC5 = 0x50000000, + /// + /// MSN 8.0 + /// + CanHandleMSNC6 = 0x60000000, + /// + /// MSN 8.1 + /// + CanHandleMSNC7 = 0x70000000, + /// + /// MSN 8.5 (MSNP15) + /// + CanHandleMSNC8 = 0x80000000, + /// + /// MSN 9.0 (MSNP16) + /// + CanHandleMSNC9 = 0x90000000, + /// + /// MSN 14.0 - Wave 3 (MSNP18) + /// + CanHandleMSNC10 = 0xA0000000, + /// + /// MSN 15.0 - Wave 4 (MSNP21) + /// + CanHandleMSNC11 = 0xB0000000, + + CanHandleMSNC12 = 0xC0000000, + CanHandleMSNC13 = 0xD0000000, + CanHandleMSNC14 = 0xE0000000, + + /// + /// Mask for MSNC + /// + CanHandleMSNCMask = 0xF0000000, + + #endregion + + #region new values + None = 0x00, + OnlineViaMobile = 0x01, + OnlineViaTexas = 0x02, + SupportsGifInk = 0x04, + SupportsIsfInk = 0x08, + WebCamDetected = 0x10, + SupportsChunking = 0x20, + MobileEnabled = 0x40, + WebWatchEnabled = 0x80, + SupportsActivities = 0x100, + OnlineViaWebIM = 0x200, + MobileDevice = 0x400, + OnlineViaFederatedInterface = 0x800, + HasSpace = 0x1000, + IsMceUser = 0x2000, + SupportsDirectIM = 0x4000, + SupportsWinks = 0x8000, + SupportsSharedSearch = 0x10000, + IsBot = 0x20000, + SupportsVoiceIM = 0x40000, + SupportsSChannel = 0x80000, + SupportsSipInvite = 0x100000, + SupportsMultipartyMedia = 0x200000, + SupportsSDrive = 0x400000, + SupportsPageModeMessaging = 0x800000, + HasOneCare = 0x1000000, + SupportsTurn = 0x2000000, + SupportsDirectBootstrapping = 0x4000000, + UsingAlias = 0x8000000, + + /// + /// MSNC1 + /// + AppVersion60 = 0x10000000, + /// + /// MSNC2 + /// + AppVersion61 = 0x20000000, + /// + /// MSNC3 + /// + AppVersion62 = 0x30000000, + /// + /// MSNC4 + /// + AppVersion70 = 0x40000000, + /// + /// MSNC5 + /// + AppVersion75 = 0x50000000, + /// + /// MSNC6 + /// + AppVersion80 = 0x60000000, + /// + ///MSNC7 + /// + AppVersion81 = 0x70000000, + /// + /// MSNC8 (MSNP15) + /// + AppVersion85 = 0x80000000, + /// + /// MSNC9 (MSNP16) + /// + AppVersion90 = 0x90000000, + /// + /// MSNC10 - MSN 14.0, Wave 3 (MSNP18) + /// + AppVersion2009 = 0xA0000000, + /// + /// MSNC11 - MSN 15.0, Wave 4 (MSNP21) + /// + AppVersion2011 = 0xB0000000, + + AppVersion____ = 0xC0000000, + AppVersion2___ = 0xD0000000, + AppVersion20__ = 0xE0000000, + + /// + /// Mask for MSNC + /// + AppVersionMask = 0xF0000000, + + Default = SupportsChunking | SupportsActivities | SupportsWinks | AppVersion2009, + #endregion + } + + [Flags] + public enum ClientCapacitiesEx : long + { + None = 0x00, + IsSmsOnly = 0x01, + SupportsVoiceOverMsnp = 0x02, + SupportsUucpSipStack = 0x04, + SupportsApplicationMessages = 0x08, + RTCVideoEnabled = 0x10, + SupportsPeerToPeerV2 = 0x20, + IsAuthenticatedWebIMUser = 0x40, + Supports1On1ViaGroup = 0x80, + SupportsOfflineIM = 0x100, + SupportsSharingVideo = 0x200, + SupportsNudges = 0x400, // (((:))) + CircleVoiceIMEnabled = 0x800, + SharingEnabled = 0x1000, + MobileSuspendIMFanoutDisable = 0x2000, + _0x4000 = 0x4000, + SupportsPeerToPeerMixerRelay = 0x8000, + _0x10000 = 0x10000, + ConvWindowFileTransfer = 0x20000, + VideoCallSupports16x9 = 0x40000, + SupportsPeerToPeerEnveloping = 0x80000, + _0x100000 = 0x100000, + _0x200000 = 0x200000, + YahooIMDisabled = 0x400000, + SIPTunnelVersion2 = 0x800000, + VoiceClipSupportsWMAFormat = 0x1000000, + VoiceClipSupportsCircleIM = 0x2000000, + SupportsSocialNewsObjectTypes = 0x4000000, + CustomEmoticonsCapable = 0x8000000, + SupportsUTF8MoodMessages = 0x10000000, + FTURNCapable = 0x20000000, + SupportsP4Activity = 0x40000000, + SupportsMultipartyConversations = 0x80000000, + + Default = SupportsPeerToPeerV2 | SupportsOfflineIM | SupportsNudges | SharingEnabled | ConvWindowFileTransfer | CustomEmoticonsCapable | SupportsUTF8MoodMessages | SupportsMultipartyConversations + } + + /// + /// The text decorations messenger sends with a message + /// + [FlagsAttribute] + public enum TextDecorations + { + /// + /// No decoration. + /// + None = 0, + /// + /// Bold. + /// + Bold = 1, + /// + /// Italic. + /// + Italic = 2, + /// + /// Underline. + /// + Underline = 4, + /// + /// Strike-trough. + /// + Strike = 8 + } + + /// + /// Types of media used on UBX command + /// + public enum MediaType + { + None = 0, + Music = 1, + Games = 2, + Office = 3 + } + + /// + /// A charset that can be used in a message. + /// + public enum MessageCharSet + { + /// + /// ANSI + /// + Ansi = 0, + /// + /// Default charset. + /// + Default = 1, + /// + /// Symbol. + /// + Symbol = 2, + /// + /// Mac. + /// + Mac = 77, + /// + /// Shiftjis. + /// + Shiftjis = 128, + /// + /// Hangeul. + /// + Hangeul = 129, + /// + /// Johab. + /// + Johab = 130, + /// + /// GB2312. + /// + GB2312 = 134, + /// + /// Chines Big 5. + /// + ChineseBig5 = 136, + /// + /// Greek. + /// + Greek = 161, + /// + /// Turkish. + /// + Turkish = 162, + /// + /// Vietnamese. + /// + Vietnamese = 163, + /// + /// Hebrew. + /// + Hebrew = 177, + /// + /// Arabic. + /// + Arabic = 178, + /// + /// Baltic. + /// + Baltic = 186, + /// + /// Russian. + /// + Russian = 204, + /// + /// Thai. + /// + Thai = 222, + /// + /// Eastern Europe. + /// + EastEurope = 238, + /// + /// OEM. + /// + Oem = 255 + } + + /// + /// Email account type. + /// If you add any new value here, remember to change the method. + /// + public enum ClientType : int + { + /// + /// No client + /// + None = 0, + + /// + /// Passport member + /// + PassportMember = 1, + + /// + /// Live Communication Server + /// + LCS = 2, + + /// + /// Phone member + /// + PhoneMember = 4, + + /// + /// MSN group + /// + CircleMember = 9, + + /// + /// Email member, currently Yahoo! + /// + EmailMember = 32 + } + + /// + /// Type of profiles that store in msn space. + /// + public enum ProfileType + { + GeneralProfile, + PublicProfile, + SocialProfile + } + + /// + /// Specifies an error a MSN Server can send. + /// + public enum MSNError + { + /// + /// No error + /// + None = 0, + /// + /// Syntax error. + /// + SyntaxError = 200, + /// + /// Invalid parameter. + /// + InvalidParameter = 201, + /// + /// Invalid contact network + /// + InvalidContactNetwork = 204, + /// + /// Invalid user. + /// + InvalidUser = 205, + /// + /// Missing domain. + /// + MissingDomain = 206, + /// + /// The user is already logged in. + /// + AlreadyLoggedIn = 207, + /// + /// The username specified is invalid. + /// + InvalidUsername = 208, + /// + /// The full username specified is invalid. + /// + InvalidFullUsername = 209, + /// + /// User's contact list is full. + /// + UserListFull = 210, + /// + /// Invalid Name Request. + /// + InvalidNameRequest = 213, + /// + /// User is already specified. + /// + UserAlreadyThere = 215, + /// + /// User is already on the list. + /// + UserAlreadyOnList = 216, + /// + /// User is not online. + /// + UserNotOnline = 217, + /// + /// Already in stated mode. + /// + AlreadyInMode = 218, + /// + /// User is in opposite (conflicting) list. + /// + UserInOppositeList = 219, + /// + /// Too Many Groups. + /// + TooManyGroups = 223, + /// + /// Invalid Group. + /// + InvalidGroup = 224, + /// + /// Principal not in group. + /// + PrincipalNotInGroup = 225, + /// + /// Principal not in group. + /// + GroupNotEmpty = 227, + /// + /// Contactgroup name already exists. + /// + ContactGroupNameExists = 228, + /// + /// Group name too long. + /// + GroupNameTooLong = 229, + /// + /// Cannot remove group zero + /// + CannotRemoveGroupZero = 230, + /// + /// If domain element specified in mail list, at least one contact must be exists + /// + EmptyDomainElement = 240, + /// + /// ADL/RML commands accept FL(1)/AL(2)/BL(4) BUT RL(8)/PL(16). + /// + InvalidMembershipForADLRML = 241, + /// + /// Switchboard request failed. + /// + SwitchboardFailed = 280, + /// + /// Switchboard transfer failed. + /// + SwitchboardTransferFailed = 281, + /// + /// P2P Error. + /// + P2PError = 282, + /// + /// Required field is missing. + /// + MissingRequiredField = 300, + /// + /// User is not logged in. + /// + NotLoggedIn = 302, + /// + /// Error accessing contact list. + /// + ErrorAccessingContactList = 402, + /// + /// Error accessing contact list. + /// + ErrorAccessingContactListRem = 403, + /// + /// Invalid account permissions. + /// + InvalidAccountPermissions = 420, + /// + /// Internal server error. + /// + InternalServerError = 500, + /// + /// Databaseserver error. + /// + DatabaseServerError = 501, + /// + /// Command Disabled. + /// + CommandDisabled = 502, + /// + /// Ups failure + /// + UpsFailure = 509, + /// + /// File operation failed. + /// + FileOperationFailed = 510, + /// + /// Banned. + /// + Banned = 511, + /// + /// Memory allocation failure. + /// + MemoryAllocationFailed = 520, + /// + /// Challenge response failed. + /// + ChallengeResponseFailed = 540, + /// + /// Server is busy. + /// + ServerIsBusy = 600, + /// + /// Server is unavailable. + /// + ServerIsUnavailable = 601, + /// + /// Nameserver is down. + /// + NameServerDown = 602, + /// + /// Database connection failed. + /// + DatabaseConnectionFailed = 603, + /// + /// Server is going down. + /// + ServerGoingDown = 604, + /// + /// Server is unavailable. + /// + ServerUnavailable = 605, + /// + /// Connection creation failed. + /// + CouldNotCreateConnection = 700, + /// + /// Bad CVR parameters sent. + /// + BadCVRParameters = 710, + /// + /// Write is blocking. + /// + WriteIsBlocking = 711, + /// + /// Session is overloaded. + /// + SessionIsOverloaded = 712, + /// + /// Calling too rapdly. + /// + CallingTooRapdly = 713, + /// + /// Too many sessions. + /// + TooManySessions = 714, + /// + /// Not expected command. + /// + NotExpected = 715, + /// + /// Bad friend file. + /// + BadFriendFile = 717, + /// + /// Not expected CVR. + /// + NotExpectedCVR = 731, + /// + /// Changing too rapdly. + /// + ChangingTooRapdly = 800, + /// + /// Server too busy. + /// + ServerTooBusy = 910, + /// + /// Authentication failed. + /// + AuthenticationFailed = 911, + /// + /// Action is not allowed when user is offline. + /// + NotAllowedWhenOffline = 913, + /// + /// New users are not accepted. + /// + NotAcceptingNewUsers = 920, + /// + /// Kids without parental consent. + /// + KidsWithoutParentalConsent = 923, + /// + /// Passport not yet verified. + /// + PassportNotYetVerified = 924, + /// + /// Bad Ticket. + /// + BadTicket = 928, + /// + /// Account not on this server + /// + AccountNotOnThisServer = 931, + /// + /// The ADL command indicates some invalid circle to server. + /// + InvalidCircleMembership = 933 + } + + /// + /// Custom emoticon type. + /// + public enum EmoticonType + { + /// + /// Emoticon that is a static picture + /// + StaticEmoticon, + /// + /// Emoticon that will display as a animation. + /// + AnimEmoticon + } + + + /// + /// The state of contact in a conversation. + /// + public enum ContactConversationState + { + None, + /// + /// The contact is invited, but not join in yet. + /// + Invited, + /// + /// The contact is in the conversation. + /// + Joined, + /// + /// The contact has left the conversation. + /// + Left + } + + /// + /// Types of different conversations. + /// + [Flags] + public enum ConversationType : long + { + /// + /// Unspecified + /// + None = 0, + /// + /// MSN user conversation. + /// + SwitchBoard = 1, + /// + /// Yahoo Messenger conversation + /// + YIM = 2, + /// + /// A conversation that contains more than 2 users. + /// + MutipleUsers = 4, + /// + /// A conversation use for chatting. + /// + Chat = 8 + } + + /// + /// Types of text messages send through switchboard. + /// + public enum NetworkMessageType : int + { + /// + /// Unspecified + /// + None = 0, + + /// + /// Plain text message + /// + Text = 1, + + /// + /// User typing message + /// + Typing = 2, + + /// + /// A nudge message + /// + Nudge = 3, + + /// + /// The emoticon data. + /// + Emoticon, + /// + /// The object data. + /// + MSNObject + } + + /// + /// CacheKey for webservices + /// + [Serializable()] + public enum CacheKeyType + { + /// + /// CacheKey for contact service, which url is ***.msnmsgr.escargot.chat + /// + OmegaContactServiceCacheKey, + + /// + /// CacheKey for profile storage service, which url is ***.storage.msn.com + /// + StorageServiceCacheKey + } + + /// + /// The current p2p version used in sb data transfer + /// + public enum P2PVersion + { + P2PV1, + P2PV2 + } + + + public static class MemberRole + { + public const string Allow = "Allow"; + public const string Block = "Block"; + public const string Reverse = "Reverse"; + public const string Pending = "Pending"; + public const string Admin = "Admin"; + public const string Contributor = "Contributor"; + public const string ProfileGeneral = "ProfileGeneral"; + public const string ProfilePersonalContact = "ProfilePersonalContact"; + public const string ProfileProfessionalContact = "ProfileProfessionalContact"; + public const string ProfileSocial = "ProfileSocial"; + public const string ProfileExpression = "ProfileExpression"; + public const string ProfileEducation = "ProfileEducation"; + public const string OneWayRelationship = "OneWayRelationship"; + public const string TwoWayRelationship = "TwoWayRelationship"; + public const string ApplicationRead = "ApplicationRead"; + public const string ApplicationWrite = "ApplicationWrite"; + } + + /// + /// Membership type. The values of fields in this class is just as the same as their names. + /// + public static class MembershipType + { + public const string Passport = "Passport"; + public const string Email = "Email"; + public const string Phone = "Phone"; + public const string Role = "Role"; + public const string Service = "Service"; + public const string Everyone = "Everyone"; + public const string Partner = "Partner"; + public const string Domain = "Domain"; + public const string Circle = "Circle"; + + } + + public static class MessengerContactType + { + public const string Me = "Me"; + public const string Regular = "Regular"; + public const string Messenger = "Messenger"; + public const string Live = "Live"; + public const string LivePending = "LivePending"; + public const string LiveRejected = "LiveRejected"; + public const string LiveDropped = "LiveDropped"; + public const string Circle = "Circle"; + } + + public static class ServiceFilterType + { + public const string Messenger = "Messenger"; + public const string Invitation = "Invitation"; + public const string SocialNetwork = "SocialNetwork"; + public const string Profile = "Profile"; + public const string Folder = "Folder"; + public const string Event = "Event"; + public const string OfficeLiveWebNotification = "OfficeLiveWebNotification"; + public const string CommunityQuestionAnswer = "CommunityQuestionAnswer"; + } + + public static class ContactPhoneTypes + { + public const string ContactPhonePersonal = "ContactPhonePersonal"; + public const string ContactPhoneBusiness = "ContactPhoneBusiness"; + public const string ContactPhoneMobile = "ContactPhoneMobile"; + public const string ContactPhonePager = "ContactPhonePager"; + public const string ContactPhoneOther = "ContactPhoneOther"; + public const string ContactPhoneFax = "ContactPhoneFax"; + public const string Personal2 = "Personal2"; + public const string Business2 = "Business2"; + public const string BusinessFax = "BusinessFax"; + public const string BusinessMobile = "BusinessMobile"; + public const string Company = "Company"; + } + + /// + /// Property string for + /// + public static class PropertyString + { + public const string propertySeparator = " "; + public const string Email = "Email"; + public const string IsMessengerEnabled = "IsMessengerEnabled"; + public const string Capability = "Capability"; + public const string Number = "Number"; + public const string Comment = "Comment"; + public const string DisplayName = "DisplayName"; + public const string Annotation = "Annotation"; + public const string IsMessengerUser = "IsMessengerUser"; + public const string MessengerMemberInfo = "MessengerMemberInfo"; + public const string ContactType = "ContactType"; + public const string ContactEmail = "ContactEmail"; + public const string ContactPhone = "ContactPhone"; + public const string GroupName = "GroupName"; + public const string HasSpace = "HasSpace"; + } + + /// + /// Scheme string for PUT command. + /// + public static class CircleString + { + /// + /// The basic pattern of messages send and receive by circles. + /// + public const string CircleMessageScheme = "{routing scheme}" + + "\r\n" + + "{reliability scheme}" + + "\r\n" + + "{message scheme}"; + + public const string RoutingScheme = "Routing: 1.0\r\n" + + "To: {to}\r\n" + + "From: {from}\r\n"; + + public const string ReliabilityScheme = "Reliability: 1.0\r\n" + + "Stream: {stream}\r\n" + + "Segment: {segment}\r\n"; + + public const string PUTCircleReplyMessageScheme = "Publication: 1.0\r\n" + + "Uri: /circle\r\n" + + "Content-Type: application/circles+xml\r\n" + + "Content-Length: {length}\r\n" + + "\r\n" + + "{xml}"; + + public const string TypingMessageScheme = "Messaging: 1.0\r\n" + + "Content-Length: 2\r\n" + + "Content-Type: text/x-msmsgscontrol\r\n" + + "Content-Transfer-Encoding: 7bit\r\n" + + "Message-Type: Control\r\n" + + "Message-Subtype: Typing\r\n" + + "MIME-Version: 1.0\r\n" + + "TypingUser: {ownermail}\r\n" + + "\r\n\r\n"; + + public const string TextMessageScheme = "Messaging: 1.0\r\n" + + "Content-Length: {length}\r\n" + + "Content-Type: Text/plain; charset=UTF-8\r\n" + + "Content-Transfer-Encoding: 7bit\r\n" + + "Message-Type: Text\r\n" + + "MIME-Version: 1.0\r\n" + + "{text message}"; + + public const string NudgeMessageScheme = "Messaging: 1.0\r\n" + + "Content-Length: 9\r\n" + + "Content-Type: Text/plain; charset=UTF-8\r\n" + + "Content-Transfer-Encoding: 7bit\r\n" + + "Message-Type: Nudge\r\n" + + "MIME-Version: 1.0\r\n" + + "\r\nID: 1\r\n\r\n"; + + public const string PUTPayloadXMLScheme = "IM1:{ownermail}"; + + public const string ToReplacementTag = "{to}"; + public const string FromReplacementTag = "{from}"; + public const string XMLReplacementTag = "{xml}"; + public const string ContentLengthReplacementTag = "{length}"; + public const string OwnerReplacementTag = "{ownermail}"; + public const string StreamReplacementTag = "{stream}"; + public const string SegmentReplacementTag = "{segment}"; + public const string RoutingSchemeReplacementTag = "{routing scheme}"; + public const string ReliabilitySchemeReplacementTag = "{reliability scheme}"; + public const string MessageSchemeReplacementTag = "{message scheme}"; + public const string TextMessageContentReplacementTag = "{text message}"; + + /// + /// The default windows live circle host domain: live.com. + /// + public const string DefaultHostDomain = "live.com"; + + /// + /// The default sender of join circle invitation email: Windows Live. + /// + public const string CircleInvitationEmailSender = "Windows Live"; + + /// + /// The extended-flags property of join circle invation email notification message. + /// + public const string InvitationEmailExtendedFlags = "ab=0|i=0|e=0"; + + public const string InvitationEmailExtendedFlagsByWeb = "ab=0|i=51|e=0"; + + /// + /// The "via" property string of a circle group member. The value of this constant is ";via=9:". + /// + public const string ViaCircleGroupSplitter = @";via=9:"; + } + + /// + /// Constants for webservice parameter. + /// + public static class WebServiceConstants + { + /// + /// The messenger's default addressbook Id: 00000000-0000-0000-0000-000000000000. + /// + public const string MessengerIndividualAddressBookId = "00000000-0000-0000-0000-000000000000"; + + /// + /// The guid for messenger group(not circle): C8529CE2-6EAD-434d-881F-341E17DB3FF8. + /// + public const string MessengerGroupType = "C8529CE2-6EAD-434d-881F-341E17DB3FF8"; + + /// + /// The default time for requesting the full membership and addressbook list: 0001-01-01T00:00:00.0000000. + /// + public const string ZeroTime = "0001-01-01T00:00:00.0000000"; + + public static string[] XmlDateTimeFormats = new string[]{ + "yyyy-MM-ddTHH:mm:ss.FFFFFFF", + "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz", + "yyyy-MM-ddTHH:mm:ss.FFFFFFFK", + "yyyy-MM-ddTHH:mm:ss", + "yyyy-MM-ddTHH:mm:ssK", + "yyyy-MM-ddTHH:mm:sszzz" + }; + } + + /// + /// Different string for Name property of + /// + public static class AnnotationNames + { + /// + /// The value is: MSN.IM.InviteMessage + /// + public const string MSN_IM_InviteMessage = "MSN.IM.InviteMessage"; + + /// + /// The value is: MSN.IM.MPOP + /// + public const string MSN_IM_MPOP = "MSN.IM.MPOP"; + + /// + /// The value is: MSN.IM.BLP + /// + public const string MSN_IM_BLP = "MSN.IM.BLP"; + + /// + /// The value is: MSN.IM.GTC + /// + public const string MSN_IM_GTC = "MSN.IM.GTC"; + + /// + /// The value is: MSN.IM.RoamLiveProperties + /// + public const string MSN_IM_RoamLiveProperties = "MSN.IM.RoamLiveProperties"; + + /// + /// The value is: MSN.IM.MBEA + /// + public const string MSN_IM_MBEA = "MSN.IM.MBEA"; + + /// + /// The value is: MSN.IM.Display + /// + public const string MSN_IM_Display = "MSN.IM.Display"; + + /// + /// The value is: MSN.IM.BuddyType + /// + public const string MSN_IM_BuddyType = "MSN.IM.BuddyType"; + + /// + /// The value is: AB.NickName + /// + public const string AB_NickName = "AB.NickName"; + + /// + /// The value is: AB.Profession + /// + public const string AB_Profession = "AB.Profession"; + + /// + /// The value is: Live.Locale + /// + public const string Live_Locale = "Live.Locale"; + + /// + /// The value is: Live.Profile.Expression.LastChanged + /// + public const string Live_Profile_Expression_LastChanged = "Live.Profile.Expression.LastChanged"; + + /// + /// The value is: Live.Passport.Birthdate + /// + public const string Live_Passport_Birthdate = "Live.Passport.Birthdate"; + } + + /// + /// The relationship between a contact and circle. + /// + public enum CirclePersonalMembershipRole : int + { + None = 0, + + /// + /// The contact is the circle admin, the value of RelationshipRole field in NetworkInfoType is 1. + /// + Admin = 1, + + /// + /// The contact is a circle co-admin, the value of RelationshipRole field in NetworkInfoType is 2. + /// + AssistantAdmin = 2, + + /// + /// The contact is a circle member, the value of RelationshipRole field in NetworkInfoType is 3. + /// + Member = 3, + + /// + /// The contact is pending to the circle, the value of RelationshipRole field in NetworkInfoType is 4. + /// + StatePendingOutbound = 4 + } + + /// + /// Mime header key constants. + /// + public static class MimeHeaderStrings + { + public const string From = "From"; + public const string To = "To"; + public const string Routing = "Routing"; + public const string Reliability = "Reliability"; + public const string Stream = "Stream"; + public const string Segment = "Segment"; + public const string Messaging = "Messaging"; + /// + /// The value is: Content-Length + /// + public const string Content_Length = "Content-Length"; + /// + /// The value is: Content-Type + /// + public const string Content_Type = "Content-Type"; + /// + /// The value is: Content-Transfer-Encoding + /// + public const string Content_Transfer_Encoding = "Content-Transfer-Encoding"; + /// + /// The value is: Message-Type + /// + public const string Message_Type = "Message-Type"; + /// + /// The value is: Message-Subtype + /// + public const string Message_Subtype = "Message-Subtype"; + /// + /// The value is: MIME-Version + /// + public const string MIME_Version = "MIME-Version"; + public const string TypingUser = "TypingUser"; + /// + /// The value is: X-MMS-IM-Format + /// + public const string X_MMS_IM_Format = "X-MMS-IM-Format"; + public const string NotifType = "NotifType"; + /// + /// The value is: P4-Context + /// + public const string P4_Context = "P4-Context"; + /// + /// The value is: Max-Forwards + /// + public const string Max_Forwards = "Max-Forwards"; + public const string Uri = "Uri"; + + internal const string KeyParam = ";"; + + } + + /// + /// The type of addressbook. + /// + public static class AddressBookType + { + /// + /// Circle. + /// + public const string Group = "Group"; + + /// + /// Default addressbook. + /// + public const string Individual = "Individual"; + } + + /// + /// The parse option for full account identifier. + /// + internal enum AccountParseOption + { + None = 0, + + /// + /// Tell the parser this is a full circle account. For example: 1:user@hotmail.com;via=9:guid@live.com + /// + ParseAsFullCircleAccount = 1, + + /// + /// Tell the parser this is a client type and account combination. For example: 1:user@hotmail.com + /// + ParseAsClientTypeAndAccount = 2 + } + + internal enum ReturnState : uint + { + None = 0, + ProcessNextContact = 1, + RequestCircleAddressBook = 2, + + /// + /// Tell the caller initialize the circle first, then recall the UpdateContact with Recall scenario. + /// + LoadAddressBookFromFile = 4, + + UpdateError = 8 + } + + internal enum Scenario : uint + { + None = 0, + + /// + /// Restoring contacts from mcl file. + /// + Restore = 1, + Initial = 2, + DeltaRequest = 4, + + /// + /// Processing the new added circles. + /// + NewCircles = 8, + + /// + /// Processing the modified circles. + /// + ModifiedCircles = 16, + + /// + /// Send the initial ADL command for contacts. + /// + SendInitialContactsADL = 32, + + /// + /// Send the initial ADL command for circles. + /// + SendInitialCirclesADL = 64, + + ContactServeAPI = 128, + + InternalCall = 256 + } + + /// + /// This is the value of different domain type of Network info list. + /// + internal static class DomainIds + { + /// + /// Domain id for Windows Live addressbook in NetworkInfo. + /// + public const int WLDomain = 1; + + /// + /// Domain ID for facebook in NetworkInfo. + /// + public const int FBDomain = 7; + public const int ZUNEDomain = 3; + } + + /// + /// The addressbook relationship types. + /// + internal static class RelationshipTypes + { + /// + /// The network info relationship is for individual addressbook (default addressbook). + /// + public const int IndividualAddressBook = 3; + + /// + /// The network info relationship is for group addressbook (circle addressbook). + /// + public const int CircleGroup = 5; + } + + /// + /// Indicates the status of contact in an addressbook. + /// + internal enum RelationshipState : uint + { + None = 0, + + /// + /// The remote circle owner invite you to join,, pending your response. + /// + WaitingResponse = 1, + + /// + /// The contact is deleted by one of the domain owners. + /// + Left = 2, + + /// + /// The contact is in the circle's addressbook list. + /// + Accepted = 3, + + /// + /// The contact already left the circle. + /// + Rejected = 4 + } + + internal enum InternalOperationReturnValues + { + Succeed, + NoExpressionProfile, + ProfileNotExist, + RequestFailed, + AddImageFailed, + AddRelationshipFailed, + AddImageRelationshipFailed + } + + public enum RosterProperties + { + None, + Name, + ClientCapacityString, + ClientCapacities, + ClientCapacitiesEx, + Status + } + + /// + /// The reason that fires event. + /// + public enum DisplayImageChangedType + { + None, + + /// + /// The is just recreate from file. + /// + Restore, + + /// + /// The is just transmitted from the remote user. + /// + TransmissionCompleted, + + /// + /// Remote user notified it has its changed. + /// + UpdateTransmissionRequired, + } + + public enum PlaceChangedReason + { + None, + SignedIn, + SignedOut + } + + #region Enums: MsnServiceType and PartnerScenario + + public enum MsnServiceType + { + AB, + Sharing, + Storage, + RSI, + OIMStore, + WhatsUp + } + + public enum PartnerScenario + { + None, + Initial, + Timer, + BlockUnblock, + GroupSave, + GeneralDialogApply, + ContactSave, + ContactMsgrAPI, + MessengerPendingList, + PrivacyApply, + NewCircleDuringPull, + CircleInvite, + CircleIdAlert, + CircleStatus, + CircleSave, + CircleLeave, + JoinedCircleDuringPush, + ABChangeNotifyAlert, + RoamingSeed, + RoamingIdentityChanged + } + + #endregion + + #region P2PFlag + + /// + /// Defines the type of P2P message. + /// + [Flags] + public enum P2PFlag : uint + { + /// + /// Normal (protocol) message. + /// + Normal = 0, + /// + /// Negative Ack + /// + NegativeAck = 0x1, + /// + /// Acknowledgement message. + /// + Acknowledgement = 0x2, + /// + /// Waiting + /// + Waiting = 0x4, + /// + /// Messages notifies a binary error. + /// + Error = 0x8, + /// + /// File + /// + File = 0x10, + /// + /// Messages defines a msn object. + /// + Data = 0x20, + /// + /// Close session + /// + CloseSession = 0x40, + /// + /// Tlp error + /// + TlpError = 0x80, + /// + /// Direct handshake + /// + DirectHandshake = 0x100, + /// + /// Messages for info data, such as INVITE, 200 OK, 500 INTERNAL ERROR + /// + MSNSLPInfo = 0x01000000, + /// + /// Messages defines data for a filetransfer. + /// + FileData = MSNSLPInfo | P2PFlag.Data | P2PFlag.File, + /// + /// Messages defines data for a MSNObject transfer. + /// + MSNObjectData = MSNSLPInfo | P2PFlag.Data + } + + #endregion + + #region P2PConst + + internal static class P2PConst + { + /// + /// The guid used in invitations for a filetransfer. + /// + public const string FileTransferGuid = "{5D3E02AB-6190-11D3-BBBB-00C04F795683}"; + + /// + /// The guid used in invitations for a user display transfer. + /// + public const string UserDisplayGuid = "{A4268EEC-FEC5-49E5-95C3-F126696BDBF6}"; + + /// + /// The guid used in invitations for a share photo. + /// + public const string SharePhotoGuid = "{41D3E74E-04A2-4B37-96F8-08ACDB610874}"; + + /// + /// The guid used in invitations for an activity. + /// + public const string ActivityGuid = "{6A13AF9C-5308-4F35-923A-67E8DDA40C2F}"; + + /// + /// Footer for a msn DisplayImage p2pMessage. + /// + public const uint DisplayImageFooter12 = 12; + + /// + /// Footer for a filetransfer p2pMessage. + /// + public const uint FileTransFooter2 = 2; + + /// + /// Footer for a msn CustomEmoticon p2pMessage. + /// + public const uint CustomEmoticonFooter11 = 11; + + /// + /// Footer for a msn object p2pMessage. + /// + public const uint DisplayImageFooter1 = 1; + + /// + /// Footer for a msn CustomEmoticon p2pMessage. + /// + public const uint CustomEmoticonFooter1 = 1; + + /// + /// The value of protocol version field of Peer info TLV. + /// + public const ushort ProtocolVersion = 512; + + /// + /// The value of implementation ID field of Peer info TLV. + /// + public const ushort ImplementationID = 0; + + /// + /// The value of version field of Peer info TLV. + /// + public const ushort PeerInfoVersion = 3584; + + /// + /// The unknown field of Peer info TLV. + /// + public const ushort PeerInfoReservedField = 0; + + /// + /// The value of capacities field of Peer info TLV. + /// + public const uint Capabilities = 271; + } + + #endregion + + #region OperationCode + + public enum OperationCode : byte + { + /// + /// Nothing required + /// + None = 0x0, + + /// + /// This is a SYN message. + /// + SYN = 0x1, + + /// + /// Required ACK. + /// + RAK = 0x2 + } + + internal enum SessionCloseState : int + { + None = 2, + TimeWait = 1, + Close = 0 + } + + internal static class MSNSLPRequestMethod + { + public const string INVITE = "INVITE"; + public const string BYE = "BYE"; + public const string ACK = "ACK"; + } + + #endregion + + public enum NetworkType + { + None, + /// + /// MSN Network + /// + WindowsLive, + /// + /// Yahoo Messenger Network. + /// + Yahoo, + /// + /// MSN mobile network. + /// + Mobile + } + + internal enum ConversationState : int + { + /// + /// Default state + /// + None = 0, + + /// + /// The conversation object created. User not yet been invited. + /// + ConversationCreated = 1, + + /// + /// Conversation has sent a request to create a switchboard for it. + /// + SwitchboardRequestSent = 2, + + /// + /// One remote user has joined into the conversation. There're two users in the conversation now (including Owner). + /// + OneRemoteUserJoined = 3, + + /// + /// The switchboard has ended. + /// + SwitchboardEnded = 4, + + /// + /// The conversation already ended. + /// + ConversationEnded = 5 + } +}; diff --git a/ProxyServer/AssemblyInfo.cs b/ProxyServer/AssemblyInfo.cs new file mode 100644 index 0000000..6c30fc9 --- /dev/null +++ b/ProxyServer/AssemblyInfo.cs @@ -0,0 +1,88 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System.Reflection; +using System.Runtime.CompilerServices; + +/* + General Information about an assembly is controlled through the following + set of attributes. Change these attribute values to modify the information + associated with an assembly. +*/ +[assembly: AssemblyTitle("Mentalis Proxy")] +[assembly: AssemblyDescription("An open source Proxy server, written in C#")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("The KPD-Team")] +[assembly: AssemblyProduct("Mentalis Proxy")] +[assembly: AssemblyCopyright("Copyright The KPD-Team, 2002")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +/* + Version information for an assembly consists of the following four values: + + Major Version + Minor Version + Build Number + Revision + + You can specify all the values or you can default the Revision and Build Numbers + by using the '*' as shown below: +*/ +[assembly: AssemblyVersion("1.0.0.*")] + +/* + In order to sign your assembly you must specify a key to use. Refer to the + Microsoft .NET Framework documentation for more information on assembly signing. + + Use the attributes below to control which key is used for signing. + + Notes: + (*) If no key is specified, the assembly is not signed. + (*) KeyName refers to a key that has been installed in the Crypto Service + Provider (CSP) on your machine. KeyFile refers to a file which contains + a key. + (*) If the KeyFile and the KeyName values are both specified, the + following processing occurs: + (1) If the KeyName can be found in the CSP, that key is used. + (2) If the KeyName does not exist and the KeyFile does exist, the key + in the KeyFile is installed into the CSP and used. + (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. + When specifying the KeyFile, the location of the KeyFile should be + relative to the project output directory which is + %Project Directory%\obj\. For example, if your KeyFile is + located in the project directory, you would specify the AssemblyKeyFile + attribute as + (*) Delay Signing is an advanced option - see the Microsoft .NET Framework + documentation for more information on this. +*/ +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/ProxyServer/AuthBase.cs b/ProxyServer/AuthBase.cs new file mode 100644 index 0000000..0151d26 --- /dev/null +++ b/ProxyServer/AuthBase.cs @@ -0,0 +1,108 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; +using Org.Mentalis.Proxy; +using Org.Mentalis.Proxy.Socks; + +namespace Org.Mentalis.Proxy.Socks.Authentication { + +///Defines the signature of the method to be called when the authentication is complete. +///Specifies whether the authentication was successfull or not. +internal delegate void AuthenticationCompleteDelegate(bool Success); + +///Authenticates a user on a SOCKS5 server according to the implemented subprotocol. +///This is an abstract class. The subprotocol that's used to authenticate a user is specified in the subclasses of this base class. +internal abstract class AuthBase { + ///Initializes a new instance of the AuthBase class. + public AuthBase() {} + ///Starts the authentication process. + ///This abstract method must be implemented in the subclasses, according to the selected subprotocol. + ///The connection with the SOCKS client. + ///The method to call when the authentication is complete. + internal abstract void StartAuthentication(Socket Connection, AuthenticationCompleteDelegate Callback); + ///Gets or sets the Socket connection between the proxy server and the SOCKS client. + ///A Socket instance defining the connection between the proxy server and the local client. + protected Socket Connection { + get { + return m_Connection; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_Connection = value; + } + } + ///Gets a buffer that can be used to receive data from the client connection. + ///An array of bytes that can be used to receive data from the client connection. + protected byte [] Buffer { + get { + return m_Buffer; + } + } + ///Gets or sets an array of bytes that can be used to store all received data. + ///An array of bytes that can be used to store all received data. + protected byte [] Bytes { + get { + return m_Bytes; + } + set { + m_Bytes = value; + } + } + ///Adds bytes to the array returned by the Bytes property. + ///The bytes to add. + ///The number of bytes to add. + protected void AddBytes(byte [] NewBytes, int Cnt) { + if (Cnt <= 0 || NewBytes == null || Cnt > NewBytes.Length) + return; + if (Bytes == null) { + Bytes = new byte[Cnt]; + } else { + byte [] tmp = Bytes; + Bytes = new byte[Bytes.Length + Cnt]; + Array.Copy(tmp, 0, Bytes, 0, tmp.Length); + } + Array.Copy(NewBytes, 0, Bytes, Bytes.Length - Cnt, Cnt); + } + ///The method to call when the authentication is complete. + protected AuthenticationCompleteDelegate Callback; + // private variables + /// Holds the value of the Connection property. + private Socket m_Connection; + /// Holds the value of the Buffer property. + private byte [] m_Buffer = new byte[1024]; + /// Holds the value of the Bytes property. + private byte [] m_Bytes; +} + +} diff --git a/ProxyServer/AuthNone.cs b/ProxyServer/AuthNone.cs new file mode 100644 index 0000000..f0a1105 --- /dev/null +++ b/ProxyServer/AuthNone.cs @@ -0,0 +1,48 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System.Net.Sockets; +using Org.Mentalis.Proxy.Socks.Authentication; + +namespace Org.Mentalis.Proxy.Socks.Authentication { + +///Authenticates a user on a SOCKS5 server according to the 'No Authentication' subprotocol. +internal sealed class AuthNone : AuthBase { + ///Initializes a new instance of the AuthNone class. + public AuthNone() {} + ///Calls the parent class to inform it authentication is complete. + ///The connection with the SOCKS client. + ///The method to call when the authentication is complete. + internal override void StartAuthentication(Socket Connection, AuthenticationCompleteDelegate Callback) { + Callback(true); + } +} + +} diff --git a/ProxyServer/AuthUserPass.cs b/ProxyServer/AuthUserPass.cs new file mode 100644 index 0000000..79fdd69 --- /dev/null +++ b/ProxyServer/AuthUserPass.cs @@ -0,0 +1,143 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Text; +using System.Net; +using System.Net.Sockets; +using Org.Mentalis.Proxy; +using Org.Mentalis.Proxy.Socks; +using Org.Mentalis.Proxy.Socks.Authentication; + +namespace Org.Mentalis.Proxy.Socks.Authentication { + +///Authenticates a user on a SOCKS5 server according to the username/password authentication subprotocol. +internal sealed class AuthUserPass : AuthBase { + ///Initializes a new instance of the AuthUserPass class. + ///An AuthenticationList object that contains the list of all valid username/password combinations. + ///If the AuthList parameter is null, any username/password combination will be accepted. + public AuthUserPass(AuthenticationList AuthList) { + this.AuthList = AuthList; + } + ///Starts the authentication process. + ///The connection with the SOCKS client. + ///The method to call when the authentication is complete. + internal override void StartAuthentication(Socket Connection, AuthenticationCompleteDelegate Callback) { + this.Connection = Connection; + this.Callback = Callback; + try { + Bytes = null; + Connection.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnRecvRequest), Connection); + } catch { + Callback(false); + } + } + ///Called when we have received the initial authentication data from the SOCKS client. + ///The result of the asynchronous operation. + private void OnRecvRequest(IAsyncResult ar) { + try { + int Ret = Connection.EndReceive(ar); + if (Ret <= 0) { + Callback(false); + return; + } + AddBytes(Buffer, Ret); + if (IsValidQuery(Bytes)) + ProcessQuery(Bytes); + else + Connection.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnRecvRequest), Connection); + } catch { + Callback(false); + } + } + ///Checks whether the specified authentication query is a valid one. + ///The query to check. + ///True if the query is a valid authentication query, false otherwise. + private bool IsValidQuery(byte [] Query) { + try { + return (Query.Length == Query[1] + Query[Query[1] + 2] + 3); + } catch { + return false; + } + } + ///Processes an authentication query. + ///The query to process. + private void ProcessQuery(byte [] Query) { + try { + string User = Encoding.ASCII.GetString(Query, 2, Query[1]); + string Pass = Encoding.ASCII.GetString(Query, Query[1] + 3, Query[Query[1] + 2]); + byte [] ToSend; + if (AuthList == null || AuthList.IsItemPresent(User, Pass)) { + ToSend = new byte[]{5, 0}; + Connection.BeginSend(ToSend, 0, ToSend.Length, SocketFlags.None, new AsyncCallback(this.OnOkSent), Connection); + } else { + ToSend = new Byte[]{5, 1}; + Connection.BeginSend(ToSend, 0, ToSend.Length, SocketFlags.None, new AsyncCallback(this.OnUhohSent), Connection); + } + } catch { + Callback(false); + } + } + ///Called when an OK reply has been sent to the client. + ///The result of the asynchronous operation. + private void OnOkSent(IAsyncResult ar) { + try { + if (Connection.EndSend(ar) <= 0) + Callback(false); + else + Callback(true); + } catch { + Callback(false); + } + } + ///Called when a negatiev reply has been sent to the client. + ///The result of the asynchronous operation. + private void OnUhohSent(IAsyncResult ar) { + try { + Connection.EndSend(ar); + } catch {} + Callback(false); + } + ///Gets or sets the AuthenticationList to use when a computer tries to authenticate on the proxy server. + ///An instance of the AuthenticationList class that contains all the valid username/password combinations. + private AuthenticationList AuthList { + get { + return m_AuthList; + } + set { + m_AuthList = value; + } + } + // private variables + /// Holds the value of the AuthList property. + private AuthenticationList m_AuthList; +} + +} diff --git a/ProxyServer/AuthenticationList.cs b/ProxyServer/AuthenticationList.cs new file mode 100644 index 0000000..38aba84 --- /dev/null +++ b/ProxyServer/AuthenticationList.cs @@ -0,0 +1,132 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Text; +using System.Security.Cryptography; +using System.Collections; +using System.Collections.Specialized; + +namespace Org.Mentalis.Proxy.Socks.Authentication { + +///Stores a dictionary with username/password combinations. +///This class can be used by a SOCKS5 listener. +///This class uses an MD5 has to store the passwords in a secure manner. +///The username is treated in a case-insensitive manner, the password is treated case-sensitive. +public class AuthenticationList { + ///Initializes a new instance of the AuthenticationList class. + public AuthenticationList() {} + ///Adds an item to the list. + ///The username to add. + ///The corresponding password to add. + ///Either Username or Password is null. + public void AddItem(string Username, string Password) { + if (Password == null) + throw new ArgumentNullException(); + AddHash(Username, Convert.ToBase64String(new MD5CryptoServiceProvider().ComputeHash(Encoding.ASCII.GetBytes(Password)))); + } + ///Adds an item to the list. + ///The username to add. + ///The hashed password to add. + ///Either Username or Password is null. + public void AddHash(string Username, string PassHash) { + if (Username == null || PassHash == null) + throw new ArgumentNullException(); + if (Listing.ContainsKey(Username)) { + Listing[Username] = PassHash; + } else { + Listing.Add(Username, PassHash); + } + } + ///Removes an item from the list. + ///The username to remove. + ///Username is null. + public void RemoveItem(string Username) { + if (Username == null) + throw new ArgumentNullException(); + Listing.Remove(Username); + } + ///Checks whether a user/pass combination is present in the collection or not. + ///The username to search for. + ///The corresponding password to search for. + ///True when the user/pass combination is present in the collection, false otherwise. + public bool IsItemPresent(string Username, string Password) { + return IsHashPresent(Username, Convert.ToBase64String(new MD5CryptoServiceProvider().ComputeHash(Encoding.ASCII.GetBytes(Password)))); + } + ///Checks whether a username is present in the collection or not. + ///The username to search for. + ///True when the username is present in the collection, false otherwise. + public bool IsUserPresent(string Username) { + return Listing.ContainsKey(Username); + } + ///Checks whether a user/passhash combination is present in the collection or not. + ///The username to search for. + ///The corresponding password hash to search for. + ///True when the user/passhash combination is present in the collection, false otherwise. + public bool IsHashPresent(string Username, string PassHash) { + return Listing.ContainsKey(Username) && Listing[Username].Equals(PassHash); + } + ///Gets the StringDictionary that's used to store the user/pass combinations. + ///A StringDictionary object that's used to store the user/pass combinations. + protected StringDictionary Listing { + get { + return m_Listing; + } + } + ///Gets an array with all the keys in the authentication list. + ///An array of strings containing all the keys in the authentication list. + public string[] Keys { + get { + ICollection keys = Listing.Keys; + string [] ret = new string[keys.Count]; + keys.CopyTo(ret, 0); + return ret; + } + } + ///Gets an array with all the hashes in the authentication list. + ///An array of strings containing all the hashes in the authentication list. + public string[] Hashes { + get { + ICollection values = Listing.Values; + string [] ret = new string[values.Count]; + values.CopyTo(ret, 0); + return ret; + } + } + ///Clears the authentication list. + public void Clear() { + Listing.Clear(); + } + // private variables + /// Holds the value of the Listing property. + private StringDictionary m_Listing = new StringDictionary(); +} + +} \ No newline at end of file diff --git a/ProxyServer/Client.cs b/ProxyServer/Client.cs new file mode 100644 index 0000000..696bf9d --- /dev/null +++ b/ProxyServer/Client.cs @@ -0,0 +1,206 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; + +namespace Org.Mentalis.Proxy { + +/// References the callback method to be called when the Client object disconnects from the local client and the remote server. +/// The Client that has closed its connections. +public delegate void DestroyDelegate(Client client); + +///Specifies the basic methods and properties of a Client object. This is an abstract class and must be inherited. +///The Client class provides an abstract base class that represents a connection to a local client and a remote server. Descendant classes further specify the protocol that is used between those two connections. +public abstract class Client : IDisposable { + ///Initializes a new instance of the Client class. + ///The Socket connection between this proxy server and the local client. + ///The callback method to be called when this Client object disconnects from the local client and the remote server. + public Client(Socket ClientSocket, DestroyDelegate Destroyer) { + this.ClientSocket = ClientSocket; + this.Destroyer = Destroyer; + } + ///Initializes a new instance of the Client object. + ///Both the ClientSocket property and the DestroyDelegate are initialized to null. + public Client() { + this.ClientSocket = null; + this.Destroyer = null; + } + ///Gets or sets the Socket connection between the proxy server and the local client. + ///A Socket instance defining the connection between the proxy server and the local client. + /// + internal Socket ClientSocket { + get { + return m_ClientSocket; + } + set { + if (m_ClientSocket != null) + m_ClientSocket.Close(); + m_ClientSocket = value; + } + } + ///Gets or sets the Socket connection between the proxy server and the remote host. + ///A Socket instance defining the connection between the proxy server and the remote host. + /// + internal Socket DestinationSocket { + get { + return m_DestinationSocket; + } + set { + if (m_DestinationSocket != null) + m_DestinationSocket.Close(); + m_DestinationSocket = value; + } + } + ///Gets the buffer to store all the incoming data from the local client. + ///An array of bytes that can be used to store all the incoming data from the local client. + /// + protected byte[] Buffer { + get { + return m_Buffer; + } + } + ///Gets the buffer to store all the incoming data from the remote host. + ///An array of bytes that can be used to store all the incoming data from the remote host. + /// + protected byte[] RemoteBuffer { + get { + return m_RemoteBuffer; + } + } + ///Disposes of the resources (other than memory) used by the Client. + ///Closes the connections with the local client and the remote host. Once Dispose has been called, this object should not be used anymore. + /// + public void Dispose() { + try { + ClientSocket.Shutdown(SocketShutdown.Both); + } catch {} + try { + DestinationSocket.Shutdown(SocketShutdown.Both); + } catch {} + //Close the sockets + if (ClientSocket != null) + ClientSocket.Close(); + if (DestinationSocket != null) + DestinationSocket.Close(); + //Clean up + ClientSocket = null; + DestinationSocket = null; + if (Destroyer != null) + Destroyer(this); + } + ///Returns text information about this Client object. + ///A string representing this Client object. + public override string ToString() { + try { + return "Incoming connection from " + ((IPEndPoint)DestinationSocket.RemoteEndPoint).Address.ToString(); + } catch { + return "Client connection"; + } + } + ///Starts relaying data between the remote host and the local client. + ///This method should only be called after all protocol specific communication has been finished. + public void StartRelay() { + try { + ClientSocket.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnClientReceive), ClientSocket); + DestinationSocket.BeginReceive(RemoteBuffer, 0, RemoteBuffer.Length, SocketFlags.None, new AsyncCallback(this.OnRemoteReceive), DestinationSocket); + } catch { + Dispose(); + } + } + ///Called when we have received data from the local client.
Incoming data will immediately be forwarded to the remote host.
+ ///The result of the asynchronous operation. + protected void OnClientReceive(IAsyncResult ar) { + try { + int Ret = ClientSocket.EndReceive(ar); + if (Ret <= 0) { + Dispose(); + return; + } + DestinationSocket.BeginSend(Buffer, 0, Ret, SocketFlags.None, new AsyncCallback(this.OnRemoteSent), DestinationSocket); + } catch { + Dispose(); + } + } + ///Called when we have sent data to the remote host.
When all the data has been sent, we will start receiving again from the local client.
+ ///The result of the asynchronous operation. + protected void OnRemoteSent(IAsyncResult ar) { + try { + int Ret = DestinationSocket.EndSend(ar); + if (Ret > 0) { + ClientSocket.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnClientReceive), ClientSocket); + return; + } + } catch {} + Dispose(); + } + ///Called when we have received data from the remote host.
Incoming data will immediately be forwarded to the local client.
+ ///The result of the asynchronous operation. + protected void OnRemoteReceive(IAsyncResult ar) { + try { + int Ret = DestinationSocket.EndReceive(ar); + if (Ret <= 0){ + Dispose(); + return; + } + ClientSocket.BeginSend(RemoteBuffer, 0, Ret, SocketFlags.None, new AsyncCallback(this.OnClientSent), ClientSocket); + } catch { + Dispose(); + } + } + ///Called when we have sent data to the local client.
When all the data has been sent, we will start receiving again from the remote host.
+ ///The result of the asynchronous operation. + protected void OnClientSent(IAsyncResult ar) { + try { + int Ret = ClientSocket.EndSend(ar); + if (Ret > 0) { + DestinationSocket.BeginReceive(RemoteBuffer, 0, RemoteBuffer.Length, SocketFlags.None, new AsyncCallback(this.OnRemoteReceive), DestinationSocket); + return; + } + } catch {} + Dispose(); + } + ///Starts communication with the local client. + public abstract void StartHandshake(); + // private variables + /// Holds the address of the method to call when this client is ready to be destroyed. + private DestroyDelegate Destroyer; + /// Holds the value of the ClientSocket property. + private Socket m_ClientSocket; + /// Holds the value of the DestinationSocket property. + private Socket m_DestinationSocket; + /// Holds the value of the Buffer property. + private byte[] m_Buffer = new byte[4096]; //0<->4095 = 4096 + /// Holds the value of the RemoteBuffer property. + private byte[] m_RemoteBuffer = new byte[1024]; +} + +} \ No newline at end of file diff --git a/ProxyServer/ConsoleAttributes.cs b/ProxyServer/ConsoleAttributes.cs new file mode 100644 index 0000000..00a5e37 --- /dev/null +++ b/ProxyServer/ConsoleAttributes.cs @@ -0,0 +1,478 @@ +/* + ConsoleAttributes class for C# + Version: 1.0 Date: 2002/04/14 +*/ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Text; +using System.Runtime.InteropServices; + +// The Org.Mentalis.Utilities.ConsoleAttributes namespace defines classes that can be used to interact with the console to change its layout and behavior. +namespace Org.Mentalis.Utilities.ConsoleAttributes { + /// + /// The CONSOLE_CURSOR_INFO structure contains information about the console cursor. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct CONSOLE_CURSOR_INFO { + /// Specifies a number between 1 and 100, indicating the percentage of the character cell that is filled by the cursor. The cursor appearance varies, ranging from completely filling the cell to showing up as a horizontal line at the bottom of the cell. + public int dwSize; + /// Specifies the visibility of the cursor. If the cursor is visible, this member is TRUE (nonzero). + public int bVisible; + } + /// + /// The COORD structure defines the coordinates of a character cell in a console screen buffer. The origin of the coordinate system (0,0) is at the top, left cell of the buffer. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct COORD { + /// Horizontal or column value. + public short x; + /// Vertical or row value. + public short y; + } + /// + /// The SMALL_RECT structure defines the coordinates of the upper left and lower right corners of a rectangle. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct SMALL_RECT { + /// Specifies the x-coordinate of the upper left corner of the rectangle. + public short Left; + /// Specifies the y-coordinate of the upper left corner of the rectangle. + public short Top; + /// Specifies the x-coordinate of the lower right corner of the rectangle. + public short Right; + /// Specifies the y-coordinate of the lower right corner of the rectangle. + public short Bottom; + } + /// + /// The CONSOLE_SCREEN_BUFFER_INFO structure contains information about a console screen buffer. + /// + [StructLayout(LayoutKind.Sequential)] + internal struct CONSOLE_SCREEN_BUFFER_INFO { + /// Specifies the size, in character columns and rows, of the screen buffer. + public COORD dwSize; + /// Specifies the column and row coordinates of the cursor in the screen buffer. + public COORD dwCursorPosition; + /// Specifies the foreground (text) and background color attributes to be used for characters that are written to a screen buffer by the WriteFile and WriteConsole functions, or echoed to a screen buffer by the ReadFile and ReadConsole functions. The attribute values are some combination of the following values: FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_RED, FOREGROUND_INTENSITY, BACKGROUND_BLUE, BACKGROUND_GREEN, BACKGROUND_RED, and BACKGROUND_INTENSITY. + public short wAttributes; + /// Specifies a SMALL_RECT structure that contains the screen buffer coordinates of the upper-left and lower-right corners of the display window. + public SMALL_RECT srWindow; + /// Specifies the maximum size of the console window, given the current screen buffer size and font and the screen size. + public COORD dwMaximumWindowSize; + } + /// Enumerates all available colors for the forecolor or the backcolor of the console. + public enum ConsoleColor : int { + /// Black + Black = 0, + /// Red + Red = 1, + /// Light red + LightRed = 2, + /// Green + Green = 3, + /// Light green + LightGreen = 4, + /// Blue + Blue = 5, + /// Light blue + LightBlue = 6, + /// Gold + Gold = 7, + /// Yellow + Yellow = 8, + /// Cyan + Cyan = 9, + /// Light cyan + LightCyan = 10, + /// Purple + Purple = 11, + /// Light purple + LightPurple = 12, + /// Gray + Gray = 13, + /// White + White = 14 + } + /// The ConsoleAttributes class can change several attributes of your console window. + /// + /// The following example wil change the forecolor of te console, disable 'EchoInput', ask for a string and show that string. + /// + /// ConsoleAttributes.ForeColor = ConsoleColor.White; + /// Console.Write("Please enter your password: "); + /// ConsoleAttributes.EchoInput = false; + /// string ThePass = Console.ReadLine(); + /// ConsoleAttributes.EchoInput = true; + /// ConsoleAttributes.ForeColor = ConsoleColor.Gray; + /// Console.WriteLine(""); + /// Console.WriteLine("The password you entered was: " + ThePass); + /// Console.WriteLine("Press enter to exit..."); + /// Console.Read(); + /// + /// + public class ConsoleAttributes { + /// + /// Lists all the possible background color values. + /// + private static int [] BacgroundColors = {0x0, 0x40, 0x80 | 0x40, 0x20, 0x80 | 0x20, 0x10, 0x80 | 0x10, 0x40 | 0x20, 0x80 | 0x40 | 0x20, 0x20 | 0x10, 0x80 | 0x20 | 0x10, 0x40 | 0x10, 0x80 | 0x40 | 0x10, 0x40 | 0x20 | 0x10, 0x80 | 0x40 | 0x20 | 0x10}; + /// + /// Lists all the possible foreground color values. + /// + private static int [] ForegroundColors = {0x0, 0x4, 0x8 | 0x4, 0x2, 0x8 | 0x2, 0x1, 0x8 | 0x1, 0x4 | 0x2, 0x8 | 0x4 | 0x2, 0x2 | 0x1, 0x8 | 0x2 | 0x1, 0x4 | 0x1, 0x8 | 0x4 | 0x1, 0x4 | 0x2 | 0x1, 0x8 | 0x4 | 0x2 | 0x1}; + /// + /// The SetConsoleTextAttribute function sets the foreground (text) and background color attributes of characters written to the screen buffer by the WriteFile or WriteConsole function, or echoed by the ReadFile or ReadConsole function. This function affects only text written after the function call. + /// + /// Handle to a console screen buffer. The handle must have GENERIC_READ access. + /// Specifies the foreground and background color attributes. Any combination of the following values can be specified: FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_RED, FOREGROUND_INTENSITY, BACKGROUND_BLUE, BACKGROUND_GREEN, BACKGROUND_RED, and BACKGROUND_INTENSITY. + /// If the function succeeds, the return value is nonzero.


If the function fails, the return value is zero. To get extended error information, call GetLastError.
+ [DllImport("KERNEL32.DLL", EntryPoint="SetConsoleTextAttribute", CharSet=CharSet.Ansi)] + internal static extern int SetConsoleTextAttribute (int hConsoleOutput, int wAttributes); + /// + /// The GetStdHandle function returns a handle for the standard input, standard output, or standard error device. + /// + /// Specifies the device for which to return the handle. This parameter can have one of the following values: + /// + /// + /// Value + /// Meaning + /// + /// + /// STD_INPUT_HANDLE + /// Standard input handle. + /// + /// + /// STD_OUTPUT_HANDLE + /// Standard output handle. + /// + /// + /// STD_ERROR_HANDLE + /// Standard error handle. + /// + /// + /// + /// If the function succeeds, the return value is a handle to the specified device.


If the function fails, the return value is the INVALID_HANDLE_VALUE flag. To get extended error information, call GetLastError.
+ [DllImport("KERNEL32.DLL", EntryPoint="GetStdHandle")] + internal static extern int GetStdHandle (int nStdHandle); + /// + /// The SetConsoleCursorInfo function sets the size and visibility of the cursor for the specified console screen buffer. + /// + /// Handle to a console screen buffer. The handle must have GENERIC_WRITE access. + /// Pointer to a CONSOLE_CURSOR_INFO structure containing the new specifications for the screen buffer's cursor. + /// If the function succeeds, the return value is nonzero.


If the function fails, the return value is zero. To get extended error information, call GetLastError.
+ [DllImport("KERNEL32.DLL", EntryPoint="SetConsoleCursorInfo")] + internal static extern int SetConsoleCursorInfo (int hConsoleOutput, ref CONSOLE_CURSOR_INFO lpConsoleCursorInfo); + /// + /// The GetConsoleMode function reports the current input mode of a console's input buffer or the current output mode of a console screen buffer. + /// + /// Handle to a console input buffer or a screen buffer. The handle must have GENERIC_READ access. + /// + /// Pointer to a 32-bit variable that indicates the current mode of the specified buffer.
If the hConsoleHandle parameter is an input handle, the mode can be a combination of the following values. When a console is created, all input modes except ENABLE_WINDOW_INPUT are enabled by default.
+ /// + /// + /// Value + /// Meaning + /// + /// + /// ENABLE_LINE_INPUT + /// The ReadFile or ReadConsole function returns only when a carriage return character is read. If this mode is disabled, the functions return when one or more characters are available. + /// + /// + /// ENABLE_ECHO_INPUT + /// Characters read by the ReadFile or ReadConsole function are written to the active screen buffer as they are read. This mode can be used only if the ENABLE_LINE_INPUT mode is also enabled. + /// + /// + /// ENABLE_PROCESSED_INPUT + /// ctrl+c is processed by the system and is not placed in the input buffer. If the input buffer is being read by ReadFile or ReadConsole, other control keys are processed by the system and are not returned in the ReadFile or ReadConsole buffer. If the ENABLE_LINE_INPUT mode is also enabled, backspace, carriage return, and linefeed characters are handled by the system. + /// + /// + /// ENABLE_WINDOW_INPUT + /// User interactions that change the size of the console screen buffer are reported in the console's input buffer. Information about these events can be read from the input buffer by applications using the ReadConsoleInput function, but not by those using ReadFile or ReadConsole. + /// + /// + /// ENABLE_MOUSE_INPUT + /// If the mouse pointer is within the borders of the console window and the window has the keyboard focus, mouse events generated by mouse movement and button presses are placed in the input buffer. These events are discarded by ReadFile or ReadConsole, even when this mode is enabled. + /// + /// + /// If the hConsoleHandle parameter is a screen buffer handle, the mode can be a combination of the following values. When a screen buffer is created, both output modes are enabled by default. + /// + /// + /// Value + /// Meaning + /// + /// + /// ENABLE_PROCESSED_OUTPUT + /// Characters written by the WriteFile or WriteConsole function or echoed by the ReadFile or ReadConsole function are parsed for ASCII control sequences, and the correct action is performed. Backspace, tab, bell, carriage return, and linefeed characters are processed. + /// + /// + /// ENABLE_WRAP_AT_EOL_OUTPUT + /// When writing with WriteFile or WriteConsole or echoing with ReadFile or ReadConsole, the cursor moves to the beginning of the next row when it reaches the end of the current row. This causes the rows displayed in the console window to scroll up automatically when the cursor advances beyond the last row in the window. It also causes the contents of the screen buffer to scroll up (discarding the top row of the screen buffer) when the cursor advances beyond the last row in the screen buffer. If this mode is disabled, the last character in the row is overwritten with any subsequent characters. + /// + /// + /// + /// If the function succeeds, the return value is nonzero.


If the function fails, the return value is zero. To get extended error information, call GetLastError.
+ [DllImport("KERNEL32.DLL", EntryPoint="GetConsoleMode")] + internal static extern int GetConsoleMode (int hConsoleHandle, ref int lpConsoleCursorInfo); + /// + /// The SetConsoleMode function sets the input mode of a console's input buffer or the output mode of a console screen buffer. + /// + /// Handle to a console input buffer or a screen buffer. The handle must have GENERIC_WRITE access. + /// + /// Pointer to a 32-bit variable that indicates the current mode of the specified buffer.
If the hConsoleHandle parameter is an input handle, the mode can be a combination of the following values. When a console is created, all input modes except ENABLE_WINDOW_INPUT are enabled by default.
+ /// + /// + /// Value + /// Meaning + /// + /// + /// ENABLE_LINE_INPUT + /// The ReadFile or ReadConsole function returns only when a carriage return character is read. If this mode is disabled, the functions return when one or more characters are available. + /// + /// + /// ENABLE_ECHO_INPUT + /// Characters read by the ReadFile or ReadConsole function are written to the active screen buffer as they are read. This mode can be used only if the ENABLE_LINE_INPUT mode is also enabled. + /// + /// + /// ENABLE_PROCESSED_INPUT + /// ctrl+c is processed by the system and is not placed in the input buffer. If the input buffer is being read by ReadFile or ReadConsole, other control keys are processed by the system and are not returned in the ReadFile or ReadConsole buffer. If the ENABLE_LINE_INPUT mode is also enabled, backspace, carriage return, and linefeed characters are handled by the system. + /// + /// + /// ENABLE_WINDOW_INPUT + /// User interactions that change the size of the console screen buffer are reported in the console's input buffer. Information about these events can be read from the input buffer by applications using the ReadConsoleInput function, but not by those using ReadFile or ReadConsole. + /// + /// + /// ENABLE_MOUSE_INPUT + /// If the mouse pointer is within the borders of the console window and the window has the keyboard focus, mouse events generated by mouse movement and button presses are placed in the input buffer. These events are discarded by ReadFile or ReadConsole, even when this mode is enabled. + /// + /// + /// If the hConsoleHandle parameter is a screen buffer handle, the mode can be a combination of the following values. When a screen buffer is created, both output modes are enabled by default. + /// + /// + /// Value + /// Meaning + /// + /// + /// ENABLE_PROCESSED_OUTPUT + /// Characters written by the WriteFile or WriteConsole function or echoed by the ReadFile or ReadConsole function are parsed for ASCII control sequences, and the correct action is performed. Backspace, tab, bell, carriage return, and linefeed characters are processed. + /// + /// + /// ENABLE_WRAP_AT_EOL_OUTPUT + /// When writing with WriteFile or WriteConsole or echoing with ReadFile or ReadConsole, the cursor moves to the beginning of the next row when it reaches the end of the current row. This causes the rows displayed in the console window to scroll up automatically when the cursor advances beyond the last row in the window. It also causes the contents of the screen buffer to scroll up (discarding the top row of the screen buffer) when the cursor advances beyond the last row in the screen buffer. If this mode is disabled, the last character in the row is overwritten with any subsequent characters. + /// + /// + /// + /// If the function succeeds, the return value is nonzero.


If the function fails, the return value is zero. To get extended error information, call GetLastError.
+ [DllImport("KERNEL32.DLL", EntryPoint="SetConsoleMode")] + internal static extern int SetConsoleMode (int hConsoleHandle, int lpConsoleCursorInfo); + /// + /// The SetConsoleTitle function sets the title bar string for the current console window. + /// + /// Pointer to a null-terminated string that contains the string to appear in the title bar of the console window. + /// If the function succeeds, the return value is nonzero.


If the function fails, the return value is zero. To get extended error information, call GetLastError.
+ [DllImport("KERNEL32.DLL", EntryPoint="SetConsoleTitleA", CharSet=CharSet.Ansi)] + internal static extern int SetConsoleTitle (string lpConsoleTitle); + /// + /// The GetConsoleTitle function retrieves the title bar string for the current console window. + /// + /// Pointer to a buffer that receives a null-terminated string containing the text that appears in the title bar of the console window. + /// Specifies the size, in characters, of the buffer pointed to by the lpConsoleTitle parameter. + /// If the function succeeds, the return value is the length, in characters, of the string copied to the buffer.


If the function fails, the return value is zero. To get extended error information, call GetLastError.
+ [DllImport("KERNEL32.DLL", EntryPoint="GetConsoleTitleA", CharSet=CharSet.Ansi)] + internal static extern int GetConsoleTitle (StringBuilder lpConsoleTitle, int nSize); + /// + /// The GetConsoleScreenBufferInfo function retrieves information about the specified console screen buffer. + /// + /// Handle to a console screen buffer. The handle must have GENERIC_READ access. + /// Pointer to a CONSOLE_SCREEN_BUFFER_INFO structure in which the screen buffer information is returned. + /// If the function succeeds, the return value is nonzero.


If the function fails, the return value is zero. To get extended error information, call GetLastError.
+ [DllImport("KERNEL32.DLL", EntryPoint="GetConsoleScreenBufferInfo")] + internal static extern int GetConsoleScreenBufferInfo (int hConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo); + /// + /// The SetConsoleCursorPosition function sets the cursor position in the specified console screen buffer. + /// + /// Handle to a console screen buffer. The handle must have GENERIC_WRITE access. + /// Specifies a COORD structure containing the new cursor position. The coordinates are the column and row of a screen buffer character cell. The coordinates must be within the boundaries of the screen buffer. + /// If the function succeeds, the return value is nonzero.


If the function fails, the return value is zero. To get extended error information, call GetLastError.
+ [DllImport("KERNEL32.DLL", EntryPoint="SetConsoleCursorPosition")] + internal static extern int SetConsoleCursorPosition (int hConsoleOutput, ref COORD dwCursorPosition); + /// Gets or sets the color of the console font. + /// A value of the ConsoleColor enum that specifies the color of the console font. + public static ConsoleColor ForeColor { + get { + return m_ForeColor; + } + set { + m_ForeColor = value; + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), ForegroundColors[(int)value] | BacgroundColors[(int)BackColor]); + } + } + /// Gets or sets the color of the console background. + /// A value of the ConsoleColor enum that specifies the color of the console background. + public static ConsoleColor BackColor { + get { + return m_BackColor; + } + set { + m_BackColor = value; + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), ForegroundColors[(int)ForeColor] | BacgroundColors[(int)value]); + } + } + /// Gets or sets whether the cursor is visible or not. + /// A boolean value that specifies the visibility of the cursor. + public static bool CursorVisible { + get { + return m_CursorVisible; + } + set { + m_CursorVisible = value; + ChangeCursor(); + } + } + /// Gets or sets whether the cursor is in overwrite-mode or not. + /// A boolean value that specifies the mode of the cursor. + /// In overwrite mode, the cursor size will be 50% of the character space instead of 25% in normal mode + public static bool OvrMode { + get { + return m_OvrMode; + } + set { + m_OvrMode = value; + ChangeCursor(); + } + } + /// Applies the current cursor settings. + /// This method applies changes in the CursorVisible and OvrMode properties. + private static void ChangeCursor() { + CONSOLE_CURSOR_INFO CCI; + CCI.bVisible = System.Convert.ToInt32(CursorVisible); + CCI.dwSize = (int)(OvrMode ? 50 : 25); + SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), ref CCI); + } + /// Gets or sets whether the console must echo the input or not. + /// A boolean value that specifies the console must echo the input or not. + /// EchoInput is often turned off when the program asks the user to type in a password. + public static bool EchoInput { + get { + return m_EchoInput; + } + set { + m_EchoInput = value; + int Ret = 0; + GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ref Ret); + if (EchoInput) + Ret = Ret | ENABLE_ECHO_INPUT; + else + Ret = Ret & ~ENABLE_ECHO_INPUT; + SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), Ret); + } + } + /// Gets or sets the caption of the console. + /// A String that specifies the caption of the console. + public static string Caption { + get { + StringBuilder sb = new StringBuilder(256); + GetConsoleTitle(sb, 256); + return sb.ToString(); + } + set { + SetConsoleTitle(value); + } + } + /// Gets or sets the current cursos position on the x axis in the console. + /// A short that specifies the current cursos position on the x axis in the console. + public static short CursorX { + get { + CONSOLE_SCREEN_BUFFER_INFO SBI = new CONSOLE_SCREEN_BUFFER_INFO(); + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), ref SBI); + return SBI.dwCursorPosition.x; + } + set { + MoveCursor(value, CursorY); + } + } + /// Gets or sets the current cursos position on the y axis in the console. + /// A short value that specifies the current cursos position on the y axis in the console. + public static short CursorY { + get { + CONSOLE_SCREEN_BUFFER_INFO SBI = new CONSOLE_SCREEN_BUFFER_INFO(); + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), ref SBI); + return SBI.dwCursorPosition.y; + } + set { + MoveCursor(CursorX, value); + } + } + /// Moves the cursor to the specified location. + /// Specifies the x value of the new location. + /// Specifies the y value of the new location. + public static void MoveCursor(short x, short y) { + COORD Crd; + Crd.x = x; + Crd.y = y; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), ref Crd); + } + /// Gets the width (in characters) of the console window. + /// An integer that holds the width of the console window in characters. + public static int WindowWidth { + get { + CONSOLE_SCREEN_BUFFER_INFO SBI = new CONSOLE_SCREEN_BUFFER_INFO(); + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), ref SBI); + return SBI.srWindow.Right - SBI.srWindow.Left + 1; + } + } + /// Gets the height (in characters) of the console window. + /// An integer that holds the height of the console window in characters. + public static int WindowHeight { + get { + CONSOLE_SCREEN_BUFFER_INFO SBI = new CONSOLE_SCREEN_BUFFER_INFO(); + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), ref SBI); + return SBI.srWindow.Bottom - SBI.srWindow.Top + 1; + } + } + // Private constants + /// Standard output handle. + private static int STD_OUTPUT_HANDLE = -11; + /// Standard input handle. + private static int STD_INPUT_HANDLE = -10; + /// Characters read by the ReadFile or ReadConsole function are written to the active screen buffer as they are read. This mode can be used only if the ENABLE_LINE_INPUT mode is also enabled. + private static int ENABLE_ECHO_INPUT = 0x4; + //Private variables + /// Holds the forecolor of the console window. + private static ConsoleColor m_ForeColor = ConsoleColor.Gray; + /// Holds the backcolor of the console window. + private static ConsoleColor m_BackColor = ConsoleColor.Black; + /// Holds the value of the CursorVisible property. + private static bool m_CursorVisible = true; + /// Holds the value of the OvrMode property. + private static bool m_OvrMode = false; + /// Holds the value of the EchoInput property. + private static bool m_EchoInput = true; +} + +} \ No newline at end of file diff --git a/ProxyServer/FtpClient.cs b/ProxyServer/FtpClient.cs new file mode 100644 index 0000000..375e8ca --- /dev/null +++ b/ProxyServer/FtpClient.cs @@ -0,0 +1,342 @@ +/* + Copyright ?2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Text; +using System.Net; +using System.Net.Sockets; +using Org.Mentalis.Proxy; + +namespace Org.Mentalis.Proxy.Ftp { + +///Relays FTP commands between a remote host and a local client. +///This class supports the 'OPEN' command, 'USER user@host:port' and 'USER user@host port'. +public sealed class FtpClient : Client { + ///Initializes a new instance of the FtpClient class. + ///The Socket connection between this proxy server and the local client. + ///The callback method to be called when this Client object disconnects from the local client and the remote server. + public FtpClient(Socket ClientSocket, DestroyDelegate Destroyer) : base(ClientSocket, Destroyer) {} + ///Sends a welcome message to the client. + public override void StartHandshake() { + try { + string ToSend = "220 Mentalis.org FTP proxy server ready.\r\n"; + ClientSocket.BeginSend(Encoding.ASCII.GetBytes(ToSend), 0, ToSend.Length, SocketFlags.None, new AsyncCallback(this.OnHelloSent), ClientSocket); + } catch { + Dispose(); + } + } + ///Called when the welcome message has been sent to the client. + ///The result of the asynchronous operation. + private void OnHelloSent(IAsyncResult ar) { + try { + if (ClientSocket.EndSend(ar) <= 0) { + Dispose(); + return; + } + ClientSocket.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceiveCommand), ClientSocket); + } catch { + Dispose(); + } + } + ///Called when we have received some bytes from the client. + ///The result of the asynchronous operation. + private void OnReceiveCommand(IAsyncResult ar) { + try { + int Ret = ClientSocket.EndReceive(ar); + string Command; + if (Ret <= 0) { + Dispose(); + return; + } + FtpCommand += Encoding.ASCII.GetString(Buffer, 0, Ret); + if (FtpClient.IsValidCommand(FtpCommand)) { + Command = FtpCommand; + if (ProcessCommand(Command)) + DestinationSocket.BeginSend(Encoding.ASCII.GetBytes(Command), 0, Command.Length, SocketFlags.None, new AsyncCallback(this.OnCommandSent), DestinationSocket); + FtpCommand = ""; + } else { + ClientSocket.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceiveCommand), ClientSocket); + } + } catch { + Dispose(); + } + } + ///Processes an FTP command, sent from the client. + ///The command to process. + ///True if the command may be sent to the server, false otherwise. + private bool ProcessCommand(string Command) { + try { + int Ret = Command.IndexOf(' '); + if (Ret < 0) + Ret = Command.Length; + switch (Command.Substring(0, Ret).ToUpper().Trim()) { + case "OPEN": + ConnectTo(ParseIPPort(Command.Substring(Ret + 1))); + break; + case "USER": + Ret = Command.IndexOf('@'); + if (Ret < 0) { + return true; + } else { + User = Command.Substring(0, Ret).Trim() + "\r\n"; + ConnectTo(ParseIPPort(Command.Substring(Ret + 1))); + } + break; + case "PORT": + ProcessPortCommand(Command.Substring(5).Trim()); + break; + case "PASV": + DataForward = new FtpDataConnection(); + DataForward.ProcessPasv(this); + return true; + default: + return true; + } + return false; + } catch { + Dispose(); + return false; + } + } + ///Processes a PORT command, sent from the client. + ///The parameters of the PORT command. + private void ProcessPortCommand(string Input) { + try { + string [] Parts = Input.Split(','); + if (Parts.Length == 6) { + DataForward = new FtpDataConnection(); + string Reply = DataForward.ProcessPort(new IPEndPoint(IPAddress.Parse(String.Join(".", Parts, 0, 4)), int.Parse(Parts[4]) * 256 + int.Parse(Parts[5]))); + DestinationSocket.BeginSend(Encoding.ASCII.GetBytes(Reply), 0, Reply.Length, SocketFlags.None, new AsyncCallback(this.OnCommandSent), DestinationSocket); + } + } catch { + Dispose(); + } + } + ///Parses an IP address and port from a specified input string. + ///The input string is of the following form:
HOST:PORT

or

HOST PORT
+ ///The string to parse. + ///An instance of the IPEndPoint class if successful, null otherwise. + private IPEndPoint ParseIPPort(string Input) { + Input = Input.Trim(); + int Ret = Input.IndexOf(':'); + if (Ret < 0) + Ret = Input.IndexOf(' '); + try { + if (Ret > 0) { + return new IPEndPoint(Dns.GetHostEntry(Input.Substring(0, Ret)).AddressList[0], int.Parse(Input.Substring(Ret + 1))); + } else { + return new IPEndPoint(Dns.GetHostEntry(Input).AddressList[0], 21); + } + } catch { + return null; + } + } + ///Connects to the specified endpoint. + ///The IPEndPoint to connect to. + ///There was an error connecting to the specified endpoint + private void ConnectTo(IPEndPoint RemoteServer) { + if (DestinationSocket != null) { + try { + DestinationSocket.Shutdown(SocketShutdown.Both); + } catch { + } finally { + DestinationSocket.Close(); + } + } + try { + DestinationSocket = new Socket(RemoteServer.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + DestinationSocket.BeginConnect(RemoteServer, new AsyncCallback(this.OnRemoteConnected), DestinationSocket); + } catch { + throw new SocketException(); + } + } + ///Called when we're connected to the remote FTP server. + ///The result of the asynchronous operation. + private void OnRemoteConnected(IAsyncResult ar) { + try { + DestinationSocket.EndConnect(ar); + ClientSocket.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceiveCommand), ClientSocket); + if (User.Equals("")) + DestinationSocket.BeginReceive(RemoteBuffer, 0, RemoteBuffer.Length, SocketFlags.None, new AsyncCallback(this.OnReplyReceived), DestinationSocket); + else + DestinationSocket.BeginReceive(RemoteBuffer, 0, RemoteBuffer.Length, SocketFlags.None, new AsyncCallback(this.OnIgnoreReply), DestinationSocket); + } catch { + Dispose(); + } + } + ///Called when we receive a reply from the FTP server that should be ignored. + ///The result of the asynchronous operation. + private void OnIgnoreReply(IAsyncResult ar) { + try { + int Ret = DestinationSocket.EndReceive(ar); + if (Ret <= 0) { + Dispose(); + return; + } + FtpReply += Encoding.ASCII.GetString(RemoteBuffer, 0, Ret); + if (FtpClient.IsValidReply(FtpReply)) { + DestinationSocket.BeginReceive(RemoteBuffer, 0, RemoteBuffer.Length, SocketFlags.None, new AsyncCallback(this.OnReplyReceived), DestinationSocket); + DestinationSocket.BeginSend(Encoding.ASCII.GetBytes(User), 0, User.Length, SocketFlags.None, new AsyncCallback(this.OnCommandSent), DestinationSocket); + } else { + DestinationSocket.BeginReceive(RemoteBuffer, 0, RemoteBuffer.Length, SocketFlags.None, new AsyncCallback(this.OnIgnoreReply), DestinationSocket); + } + } catch { + Dispose(); + } + } + ///Called when an FTP command has been successfully sent to the FTP server. + ///The result of the asynchronous operation. + private void OnCommandSent(IAsyncResult ar) { + try { + if (DestinationSocket.EndSend(ar) <= 0) { + Dispose(); + return; + } + ClientSocket.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceiveCommand), ClientSocket); + } catch { + Dispose(); + } + } + ///Called when we receive a reply from the FTP server. + ///The result of the asynchronous operation. + private void OnReplyReceived(IAsyncResult ar) { + try { + int Ret = DestinationSocket.EndReceive(ar); + if (Ret <= 0) { + Dispose(); + return; + } + if (DataForward != null && DataForward.ExpectsReply) { + if (!DataForward.ProcessPasvReplyRecv(Encoding.ASCII.GetString(RemoteBuffer, 0, Ret))) + DestinationSocket.BeginReceive(RemoteBuffer, 0, RemoteBuffer.Length, SocketFlags.None, new AsyncCallback(this.OnReplyReceived), DestinationSocket); + } else { + ClientSocket.BeginSend(RemoteBuffer, 0, Ret, SocketFlags.None, new AsyncCallback(this.OnReplySent), ClientSocket); + } + } catch { + Dispose(); + } + } + ///Called when the reply from the FTP server has been sent to the local FTP client. + ///The result of the asynchronous operation. + private void OnReplySent(IAsyncResult ar) { + try { + int Ret = ClientSocket.EndSend(ar); + if (Ret <= 0) { + Dispose(); + return; + } + DestinationSocket.BeginReceive(RemoteBuffer, 0, RemoteBuffer.Length, SocketFlags.None, new AsyncCallback(this.OnReplyReceived), DestinationSocket); + } catch { + Dispose(); + } + } + ///Sends a string to the local FTP client. + ///The result of the asynchronous operation. + internal void SendCommand(string Command) { + ClientSocket.BeginSend(Encoding.ASCII.GetBytes(Command), 0, Command.Length, SocketFlags.None, new AsyncCallback(this.OnReplySent), ClientSocket); + } + ///Checks whether a specified command is a complete FTP command or not. + ///A string containing the command to check. + ///True if the command is complete, false otherwise. + internal static bool IsValidCommand(string Command) { + return (Command.IndexOf("\r\n") >= 0); + } + ///Checks whether a specified reply is a complete FTP reply or not. + ///A string containing the reply to check. + ///True is the reply is complete, false otherwise. + internal static bool IsValidReply(string Input) { + string [] Lines = Input.Split('\n'); + try { + if (Lines[Lines.Length - 2].Trim().Substring(3, 1).Equals(" ")) + return true; + } catch {} + return false; + } + ///Gets or sets a property that can be used to store the received FTP command. + ///A string that can be used to store the received FTP command. + private string FtpCommand { + get { + return m_FtpCommand; + } + set { + m_FtpCommand = value; + } + } + ///Gets or sets a property that can be used to store the received FTP reply. + ///A string that can be used to store the received FTP reply. + private string FtpReply { + get { + return m_FtpReply; + } + set { + m_FtpReply = value; + } + } + ///Gets or sets a string containing the logged on username. + ///A string containing the logged on username. + private string User { + get { + return m_User; + } + set { + m_User = value; + } + } + ///Gets or sets the dataconnection object used to transmit files and other data from and to the FTP server. + ///An FtpDataConnection object that's used to transmit files and other data from and to the FTP server. + internal FtpDataConnection DataForward { + get { + return m_DataForward; + } + set { + m_DataForward = value; + } + } + ///Returns text information about this FtpClient object. + ///A string representing this FtpClient object. + public override string ToString() { + try { + return "FTP connection from " + ((IPEndPoint)ClientSocket.RemoteEndPoint).Address.ToString() + " to " + ((IPEndPoint)DestinationSocket.RemoteEndPoint).Address.ToString(); + } catch { + return "Incoming FTP connection"; + } + } + // private variables + /// Holds the value of the User property. + private string m_User = ""; + /// Holds the value of the FtpCommand property. + private string m_FtpCommand = ""; + /// Holds the value of the FtpReply property. + private string m_FtpReply = ""; + /// Holds the value of the DataForward property. + private FtpDataConnection m_DataForward; +} + +} diff --git a/ProxyServer/FtpDataConnection.cs b/ProxyServer/FtpDataConnection.cs new file mode 100644 index 0000000..eb1b8a0 --- /dev/null +++ b/ProxyServer/FtpDataConnection.cs @@ -0,0 +1,216 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Text; +using System.Net; +using System.Net.Sockets; +using Org.Mentalis.Proxy; + +namespace Org.Mentalis.Proxy.Ftp { + +///Relays FTP data between a remote host and a local client. +internal sealed class FtpDataConnection : Client { + ///Initializes a new instance of the FtpDataConnection class. + public FtpDataConnection() : base() {} + ///Initializes a new instance of the FtpDataConnection class. + ///The address on the local FTP client to connect to. + ///The PORT command string to send to the FTP server. + public string ProcessPort(IPEndPoint RemoteAddress) { + try { + ListenSocket = new Socket(IPAddress.Any.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + ListenSocket.Bind(new IPEndPoint(IPAddress.Any, 0)); + ListenSocket.Listen(1); + ListenSocket.BeginAccept(new AsyncCallback(this.OnPortAccept), ListenSocket); + ClientSocket = new Socket(RemoteAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + ClientSocket.BeginConnect(RemoteAddress, new AsyncCallback(this.OnPortConnected), ClientSocket); + return "PORT " + Listener.GetLocalExternalIP().ToString().Replace('.', ',') + "," + Math.Floor((double)((IPEndPoint)ListenSocket.LocalEndPoint).Port / 256).ToString() + "," + (((IPEndPoint)ListenSocket.LocalEndPoint).Port % 256).ToString() + "\r\n"; + } catch { + Dispose(); + return "PORT 0,0,0,0,0,0\r\n"; + } + } + ///Called when we're connected to the data port on the local FTP client. + ///The result of the asynchronous operation. + private void OnPortConnected(IAsyncResult ar) { + try { + ClientSocket.EndConnect(ar); + StartHandshake(); + } catch { + Dispose(); + } + } + ///Called when there's a connection from the remote FTP server waiting to be accepted. + ///The result of the asynchronous operation. + private void OnPortAccept(IAsyncResult ar) { + try { + DestinationSocket = ListenSocket.EndAccept(ar); + ListenSocket.Close(); + ListenSocket = null; + StartHandshake(); + } catch { + Dispose(); + } + } + ///Starts relaying data between the remote FTP server and the local FTP client. + public override void StartHandshake() { + if (DestinationSocket != null && ClientSocket != null && DestinationSocket.Connected && ClientSocket.Connected) + StartRelay(); + } + ///Gets or sets the Socket that's used to listen for incoming connections. + ///A Socket that's used to listen for incoming connections. + private Socket ListenSocket { + get { + return m_ListenSocket; + } + set { + if (m_ListenSocket != null) + m_ListenSocket.Close(); + m_ListenSocket = value; + } + } + ///Gets or sets the parent of this FtpDataConnection. + ///The FtpClient object that's the parent of this FtpDataConnection object. + private FtpClient Parent { + get { + return m_Parent; + } + set { + m_Parent = value; + } + } + ///Gets or sets a string that stores the reply that has been sent from the remote FTP server. + ///A string that stores the reply that has been sent from the remote FTP server. + private string FtpReply { + get { + return m_FtpReply; + } + set { + m_FtpReply = value; + } + } + ///Gets or sets a boolean value that indicates whether the FtpDataConnection expects a reply from the remote FTP server or not. + ///A boolean value that indicates whether the FtpDataConnection expects a reply from the remote FTP server or not. + internal bool ExpectsReply { + get { + return m_ExpectsReply; + } + set { + m_ExpectsReply = value; + } + } + ///Called when the proxy server processes a PASV command. + ///The parent FtpClient object. + public void ProcessPasv(FtpClient Parent) { + this.Parent = Parent; + ExpectsReply = true; + } + ///Called when the FtpClient receives a reply on the PASV command from the server. + ///The received reply. + ///True if the input has been processed successfully, false otherwise. + internal bool ProcessPasvReplyRecv(string Input) { + FtpReply += Input; + if (FtpClient.IsValidReply(FtpReply)) { + ExpectsReply = false; + ProcessPasvReply(FtpReply); + FtpReply = ""; + return true; + } + return false; + } + ///Processes a PASV reply from the server. + ///The reply to process. + private void ProcessPasvReply(string Reply) { + try { + IPEndPoint ConnectTo = ParsePasvIP(Reply); + DestinationSocket = new Socket(ConnectTo.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + DestinationSocket.BeginConnect(ConnectTo, new AsyncCallback(this.OnPasvConnected), DestinationSocket); + } catch { + Dispose(); + } + } + ///Parses a PASV reply into an instance of the IPEndPoint class. + ///The reply to parse into an IPEndPoint. + ///An instance of the IPEndPoint class when successful, null otherwise. + private IPEndPoint ParsePasvIP(string Reply) { + int StartIndex, StopIndex; + string IPString; + StartIndex = Reply.IndexOf("("); + if (StartIndex == -1) { + return null; + } else { + StopIndex = Reply.IndexOf(")", StartIndex); + if (StopIndex == -1) + return null; + else + IPString = Reply.Substring(StartIndex + 1, StopIndex - StartIndex - 1); + } + string [] Parts = IPString.Split(','); + if (Parts.Length == 6) + return new IPEndPoint(IPAddress.Parse(String.Join(".", Parts, 0, 4)), int.Parse(Parts[4]) * 256 + int.Parse(Parts[5])); + else + return null; + } + ///Called when we're connected to the data port of the remote FTP server. + ///The result of the asynchronous operation. + private void OnPasvConnected(IAsyncResult ar) { + try { + DestinationSocket.EndConnect(ar); + ListenSocket = new Socket(IPAddress.Any.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + ListenSocket.Bind(new IPEndPoint(IPAddress.Any, 0)); + ListenSocket.Listen(1); + ListenSocket.BeginAccept(new AsyncCallback(this.OnPasvAccept), ListenSocket); + Parent.SendCommand("227 Entering Passive Mode (" + Listener.GetLocalInternalIP().ToString().Replace('.', ',') + "," + Math.Floor((double)((IPEndPoint)ListenSocket.LocalEndPoint).Port / 256).ToString() + "," + (((IPEndPoint)ListenSocket.LocalEndPoint).Port % 256).ToString() + ").\r\n"); + } catch { + Dispose(); + } + } + ///Called when there's a connection from the local FTP client waiting to be accepted. + ///The result of the asynchronous operation. + private void OnPasvAccept(IAsyncResult ar) { + try { + ClientSocket = ListenSocket.EndAccept(ar); + StartHandshake(); + } catch { + Dispose(); + } + } + // private variables + /// Holds the value of the ListenSocket property. + private Socket m_ListenSocket; + /// Holds the value of the Parent property. + private FtpClient m_Parent; + /// Holds the value of the FtpReply property. + private string m_FtpReply = ""; + /// Holds the value of the ExpectsReply property. + private bool m_ExpectsReply = false; +} + +} diff --git a/ProxyServer/FtpListener.cs b/ProxyServer/FtpListener.cs new file mode 100644 index 0000000..a5c711f --- /dev/null +++ b/ProxyServer/FtpListener.cs @@ -0,0 +1,83 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; +using Org.Mentalis.Proxy; + +namespace Org.Mentalis.Proxy.Ftp { + +///Listens on a specific port on the proxy server and forwards all incoming FTP traffic to the appropriate server. +public sealed class FtpListener : Listener { + ///Initializes a new instance of the FtpListener class. + ///The port to listen on. + ///The FtpListener will start listening on all installed network cards. + ///Port is not positive. + public FtpListener(int Port) : this(IPAddress.Any, Port) {} + ///Initializes a new instance of the FtpListener class. + ///The port to listen on. + ///The address to listen on. You can specify IPAddress.Any to listen on all installed network cards. + ///For the security of your server, try to avoid to listen on every network card (IPAddress.Any). Listening on a local IP address is usually sufficient and much more secure. + ///Address is null. + ///Port is not positive. + public FtpListener(IPAddress Address, int Port) : base(Port, Address) {} + ///Called when there's an incoming client connection waiting to be accepted. + ///The result of the asynchronous operation. + public override void OnAccept(IAsyncResult ar) { + try { + Socket NewSocket = ListenSocket.EndAccept(ar); + if (NewSocket != null) { + FtpClient NewClient = new FtpClient(NewSocket, new DestroyDelegate(this.RemoveClient)); + AddClient(NewClient); + NewClient.StartHandshake(); + } + } catch {} + try { + ListenSocket.BeginAccept(new AsyncCallback(this.OnAccept), ListenSocket); + } catch { + Dispose(); + } + } + ///Returns a string representation of this object. + ///A string with information about this object. + public override string ToString() { + return "FTP service on " + Address.ToString() + ":" + Port.ToString(); + } + ///Returns a string that holds all the construction information for this object. + ///A string that holds all the construction information for this object. + public override string ConstructString { + get { + return "host:" + Address.ToString() + ";int:" + Port.ToString(); + } + } +} + +} diff --git a/ProxyServer/HttpClient.cs b/ProxyServer/HttpClient.cs new file mode 100644 index 0000000..8cfd276 --- /dev/null +++ b/ProxyServer/HttpClient.cs @@ -0,0 +1,368 @@ +/* + Copyright ?2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Text; +using System.Net.Sockets; +using System.Collections; +using System.Collections.Specialized; +using System.Threading; +using System.Globalization; +using Org.Mentalis.Proxy; + +namespace Org.Mentalis.Proxy.Http { + +///Relays HTTP data between a remote host and a local client. +///This class supports both HTTP and HTTPS. +public sealed class HttpClient : Client { + ///Initializes a new instance of the HttpClient class. + ///The Socket connection between this proxy server and the local client. + ///The callback method to be called when this Client object disconnects from the local client and the remote server. + public HttpClient(Socket ClientSocket, DestroyDelegate Destroyer) : base(ClientSocket, Destroyer) {} + ///Gets or sets a StringDictionary that stores the header fields. + ///A StringDictionary that stores the header fields. + private StringDictionary HeaderFields { + get { + return m_HeaderFields; + } + set { + m_HeaderFields = value; + } + } + ///Gets or sets the HTTP version the client uses. + ///A string representing the requested HTTP version. + private string HttpVersion { + get { + return m_HttpVersion; + } + set { + m_HttpVersion = value; + } + } + ///Gets or sets the HTTP request type. + /// + ///Usually, this string is set to one of the three following values: + /// + ///GET + ///POST + ///CONNECT + /// + /// + ///A string representing the HTTP request type. + private string HttpRequestType { + get { + return m_HttpRequestType; + } + set { + m_HttpRequestType = value; + } + } + ///Gets or sets the requested path. + ///A string representing the requested path. + public string RequestedPath { + get { + return m_RequestedPath; + } + set { + m_RequestedPath = value; + } + } + ///Gets or sets the query string, received from the client. + ///A string representing the HTTP query string. + private string HttpQuery { + get { + return m_HttpQuery; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_HttpQuery = value; + } + } + ///Starts receiving data from the client connection. + public override void StartHandshake() { + try { + ClientSocket.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceiveQuery), ClientSocket); + } catch { + Dispose(); + } + } + ///Checks whether a specified string is a valid HTTP query string. + ///The query to check. + ///True if the specified string is a valid HTTP query, false otherwise. + private bool IsValidQuery(string Query) { + int index = Query.IndexOf("\r\n\r\n"); + if (index == -1) + return false; + HeaderFields = ParseQuery(Query); + if (HttpRequestType.ToUpper().Equals("POST")) { + try { + int length = int.Parse((string)HeaderFields["Content-Length"]); + return Query.Length >= index + 6 + length; + } catch { + SendBadRequest(); + return true; + } + } else { + return true; + } + } + ///Processes a specified query and connects to the requested HTTP web server. + ///A string containing the query to process. + ///If there's an error while processing the HTTP request or when connecting to the remote server, the Proxy sends a "400 - Bad Request" error to the client. + private void ProcessQuery(string Query) { + HeaderFields = ParseQuery(Query); + if (HeaderFields == null || !HeaderFields.ContainsKey("Host")) { + SendBadRequest(); + return; + } + int Port; + string Host; + int Ret; + if (HttpRequestType.ToUpper().Equals("CONNECT")) { //HTTPS + Ret = RequestedPath.IndexOf(":"); + if (Ret >= 0) { + Host = RequestedPath.Substring(0, Ret); + if (RequestedPath.Length > Ret + 1) + Port = int.Parse(RequestedPath.Substring(Ret + 1)); + else + Port = 443; + } else { + Host = RequestedPath; + Port = 443; + } + } else { //Normal HTTP + Ret = ((string)HeaderFields["Host"]).IndexOf(":"); + if (Ret > 0) { + Host = ((string)HeaderFields["Host"]).Substring(0, Ret); + Port = int.Parse(((string)HeaderFields["Host"]).Substring(Ret + 1)); + } else { + Host = (string)HeaderFields["Host"]; + Port = 80; + } + if (HttpRequestType.ToUpper().Equals("POST")) { + int index = Query.IndexOf("\r\n\r\n"); + m_HttpPost = Query.Substring(index + 4); + } + } + try { + IPEndPoint DestinationEndPoint = new IPEndPoint(Dns.GetHostEntry(Host).AddressList[0], Port); + DestinationSocket = new Socket(DestinationEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + if (HeaderFields.ContainsKey("Proxy-Connection") && HeaderFields["Proxy-Connection"].ToLower(CultureInfo.InvariantCulture).Equals("keep-alive")) + DestinationSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, 1); + DestinationSocket.BeginConnect(DestinationEndPoint, new AsyncCallback(this.OnConnected), DestinationSocket); + } catch { + SendBadRequest(); + return; + } + } + ///Parses a specified HTTP query into its header fields. + ///The HTTP query string to parse. + ///A StringDictionary object containing all the header fields with their data. + ///The specified query is null. + private StringDictionary ParseQuery(string Query) { + StringDictionary retdict = new StringDictionary(); + string [] Lines = Query.Replace("\r\n", "\n").Split('\n'); + int Cnt, Ret; + //Extract requested URL + if (Lines.Length > 0) { + //Parse the Http Request Type + Ret = Lines[0].IndexOf(' '); + if (Ret > 0) { + HttpRequestType = Lines[0].Substring(0, Ret); + Lines[0] = Lines[0].Substring(Ret).Trim(); + } + //Parse the Http Version and the Requested Path + Ret = Lines[0].LastIndexOf(' '); + if (Ret > 0) { + HttpVersion = Lines[0].Substring(Ret).Trim(); + RequestedPath = Lines[0].Substring(0, Ret); + } else { + RequestedPath = Lines[0]; + } + //Remove http:// if present + if (RequestedPath.Length >= 7 && RequestedPath.Substring(0, 7).ToLower(CultureInfo.InvariantCulture).Equals("http://")) { + Ret = RequestedPath.IndexOf('/', 7); + if (Ret == -1) + RequestedPath = "/"; + else + RequestedPath = RequestedPath.Substring(Ret); + } + } + for(Cnt = 1; Cnt < Lines.Length; Cnt++) { + Ret = Lines[Cnt].IndexOf(":"); + if (Ret > 0 && Ret < Lines[Cnt].Length - 1) { + try { + retdict.Add(Lines[Cnt].Substring(0, Ret), Lines[Cnt].Substring(Ret + 1).Trim()); + } catch {} + } + } + return retdict; + } + ///Sends a "400 - Bad Request" error to the client. + private void SendBadRequest() { + string brs = "HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-Type: text/html\r\n\r\n400 Bad Request

400 Bad Request

The proxy server could not understand the HTTP request!

Please contact your network administrator about this problem.
"; + try { + ClientSocket.BeginSend(Encoding.ASCII.GetBytes(brs), 0, brs.Length, SocketFlags.None, new AsyncCallback(this.OnErrorSent), ClientSocket); + } catch { + Dispose(); + } + } + ///Rebuilds the HTTP query, starting from the HttpRequestType, RequestedPath, HttpVersion and HeaderFields properties. + ///A string representing the rebuilt HTTP query string. + private string RebuildQuery() { + string ret = HttpRequestType + " " + RequestedPath + " " + HttpVersion + "\r\n"; + if (HeaderFields != null) { + foreach (string sc in HeaderFields.Keys) { + if (sc.Length < 6 || !sc.Substring(0, 6).Equals("proxy-")) + ret += System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(sc) + ": " + (string)HeaderFields[sc] + "\r\n"; + } + ret += "\r\n"; + if (m_HttpPost != null) + ret += m_HttpPost; + } + return ret; + } + ///Returns text information about this HttpClient object. + ///A string representing this HttpClient object. + public override string ToString() { + return ToString(false); + } + ///Returns text information about this HttpClient object. + ///A string representing this HttpClient object. + ///Specifies whether or not to include information about the requested URL. + public string ToString(bool WithUrl) { + string Ret; + try { + if (DestinationSocket == null || DestinationSocket.RemoteEndPoint == null) + Ret = "Incoming HTTP connection from " + ((IPEndPoint)ClientSocket.RemoteEndPoint).Address.ToString(); + else + Ret = "HTTP connection from " + ((IPEndPoint)ClientSocket.RemoteEndPoint).Address.ToString() + " to " + ((IPEndPoint)DestinationSocket.RemoteEndPoint).Address.ToString() + " on port " + ((IPEndPoint)DestinationSocket.RemoteEndPoint).Port.ToString(); + if (HeaderFields != null && HeaderFields.ContainsKey("Host") && RequestedPath != null) + Ret += "\r\n" + " requested URL: http://" + HeaderFields["Host"] + RequestedPath; + } catch { + Ret = "HTTP Connection"; + } + return Ret; + } + ///Called when we received some data from the client connection. + ///The result of the asynchronous operation. + private void OnReceiveQuery(IAsyncResult ar) { + int Ret; + try { + Ret = ClientSocket.EndReceive(ar); + } catch { + Ret = -1; + } + if (Ret <= 0) { //Connection is dead :( + Dispose(); + return; + } + HttpQuery += Encoding.ASCII.GetString(Buffer, 0, Ret); + //if received data is valid HTTP request... + if (IsValidQuery(HttpQuery)) { + ProcessQuery(HttpQuery); + //else, keep listening + } else { + try { + ClientSocket.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceiveQuery), ClientSocket); + } catch { + Dispose(); + } + } + } + ///Called when the Bad Request error has been sent to the client. + ///The result of the asynchronous operation. + private void OnErrorSent(IAsyncResult ar) { + try { + ClientSocket.EndSend(ar); + } catch {} + Dispose(); + } + ///Called when we're connected to the requested remote host. + ///The result of the asynchronous operation. + private void OnConnected(IAsyncResult ar) { + try { + DestinationSocket.EndConnect(ar); + string rq; + if (HttpRequestType.ToUpper().Equals("CONNECT")) { //HTTPS + rq = HttpVersion + " 200 Connection established\r\nProxy-Agent: Mentalis Proxy Server\r\n\r\n"; + ClientSocket.BeginSend(Encoding.ASCII.GetBytes(rq), 0, rq.Length, SocketFlags.None, new AsyncCallback(this.OnOkSent), ClientSocket); + } else { //Normal HTTP + rq = RebuildQuery(); + DestinationSocket.BeginSend(Encoding.ASCII.GetBytes(rq), 0, rq.Length, SocketFlags.None, new AsyncCallback(this.OnQuerySent), DestinationSocket); + } + } catch { + Dispose(); + } + } + ///Called when the HTTP query has been sent to the remote host. + ///The result of the asynchronous operation. + private void OnQuerySent(IAsyncResult ar) { + try { + if (DestinationSocket.EndSend(ar) == -1) { + Dispose(); + return; + } + StartRelay(); + } catch { + Dispose(); + } + } + ///Called when an OK reply has been sent to the local client. + ///The result of the asynchronous operation. + private void OnOkSent(IAsyncResult ar) { + try { + if (ClientSocket.EndSend(ar) == -1) { + Dispose(); + return; + } + StartRelay(); + } catch { + Dispose(); + } + } + // private variables + /// Holds the value of the HttpQuery property. + private string m_HttpQuery = ""; + /// Holds the value of the RequestedPath property. + private string m_RequestedPath = null; + /// Holds the value of the HeaderFields property. + private StringDictionary m_HeaderFields = null; + /// Holds the value of the HttpVersion property. + private string m_HttpVersion = ""; + /// Holds the value of the HttpRequestType property. + private string m_HttpRequestType = ""; + /// Holds the POST data + private string m_HttpPost = null; +} + +} diff --git a/ProxyServer/HttpListener.cs b/ProxyServer/HttpListener.cs new file mode 100644 index 0000000..f5b883e --- /dev/null +++ b/ProxyServer/HttpListener.cs @@ -0,0 +1,81 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; +using Org.Mentalis.Proxy; + +namespace Org.Mentalis.Proxy.Http { + +///Listens on a specific port on the proxy server and forwards all incoming HTTP traffic to the appropriate server. +public sealed class HttpListener : Listener { + ///Initializes a new instance of the HttpListener class. + ///The port to listen on. + ///The HttpListener will start listening on all installed network cards. + public HttpListener(int Port) : this(IPAddress.Any, Port) {} + ///Initializes a new instance of the HttpListener class. + ///The port to listen on. + ///The address to listen on. You can specify IPAddress.Any to listen on all installed network cards. + ///For the security of your server, try to avoid to listen on every network card (IPAddress.Any). Listening on a local IP address is usually sufficient and much more secure. + public HttpListener(IPAddress Address, int Port) : base(Port, Address) {} + ///Called when there's an incoming client connection waiting to be accepted. + ///The result of the asynchronous operation. + public override void OnAccept(IAsyncResult ar) { + try { + Socket NewSocket = ListenSocket.EndAccept(ar); + if (NewSocket != null) { + HttpClient NewClient = new HttpClient(NewSocket, new DestroyDelegate(this.RemoveClient)); + AddClient(NewClient); + NewClient.StartHandshake(); + } + } catch {} + try { + //Restart Listening + ListenSocket.BeginAccept(new AsyncCallback(this.OnAccept), ListenSocket); + } catch { + Dispose(); + } + } + ///Returns a string representation of this object. + ///A string with information about this object. + public override string ToString() { + return "HTTP service on " + Address.ToString() + ":" + Port.ToString(); + } + ///Returns a string that holds all the construction information for this object. + ///A string that holds all the construction information for this object. + public override string ConstructString { + get { + return "host:" + Address.ToString() + ";int:" + Port.ToString(); + } + } +} + +} diff --git a/ProxyServer/Listener.cs b/ProxyServer/Listener.cs new file mode 100644 index 0000000..512bfcb --- /dev/null +++ b/ProxyServer/Listener.cs @@ -0,0 +1,261 @@ +/* + Copyright ?2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; +using System.Collections; + +namespace Org.Mentalis.Proxy { + +///Specifies the basic methods and properties of a Listener object. This is an abstract class and must be inherited. +///The Listener class provides an abstract base class that represents a listening socket of the proxy server. Descendant classes further specify the protocol that is used between those two connections. +public abstract class Listener : IDisposable{ + ///Initializes a new instance of the Listener class. + ///The port to listen on. + ///The address to listen on. You can specify IPAddress.Any to listen on all installed network cards. + ///For the security of your server, try to avoid to listen on every network card (IPAddress.Any). Listening on a local IP address is usually sufficient and much more secure. + public Listener (int Port, IPAddress Address){ + this.Port = Port; + this.Address = Address; + } + ///Gets or sets the port number on which to listen on. + ///An integer defining the port number to listen on. + /// + ///The specified value is less than or equal to zero. + protected int Port { + get { + return m_Port; + } + set { + if (value <= 0) + throw new ArgumentException(); + m_Port = value; + Restart(); + } + } + ///Gets or sets the address on which to listen on. + ///An IPAddress instance defining the IP address to listen on. + /// + ///The specified value is null. + protected IPAddress Address { + get { + return m_Address; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_Address = value; + Restart(); + } + } + ///Gets or sets the listening Socket. + ///An instance of the Socket class that's used to listen for incoming connections. + ///The specified value is null. + protected Socket ListenSocket { + get { + return m_ListenSocket; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_ListenSocket = value; + } + } + ///Gets the list of connected clients. + ///An instance of the ArrayList class that's used to store all the connections. + protected ArrayList Clients { + get { + return m_Clients; + } + } + ///Gets a value indicating whether the Listener has been disposed or not. + ///An boolean that specifies whether the object has been disposed or not. + public bool IsDisposed { + get { + return m_IsDisposed; + } + } + ///Starts listening on the selected IP address and port. + ///There was an error while creating the listening socket. + public void Start() { + try { + ListenSocket = new Socket(Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + ListenSocket.Bind(new IPEndPoint(Address, Port)); + ListenSocket.Listen(50); + ListenSocket.BeginAccept(new AsyncCallback(this.OnAccept), ListenSocket); + } catch { + ListenSocket = null; + throw new SocketException(); + } + } + ///Restarts listening on the selected IP address and port. + ///This method is automatically called when the listening port or the listening IP address are changed. + ///There was an error while creating the listening socket. + protected void Restart() { + //If we weren't listening, do nothing + if (ListenSocket == null) + return; + ListenSocket.Close(); + Start(); + } + ///Adds the specified Client to the client list. + ///A client will never be added twice to the list. + ///The client to add to the client list. + protected void AddClient(Client client) { + if (Clients.IndexOf(client) == -1) + Clients.Add(client); + } + ///Removes the specified Client from the client list. + ///The client to remove from the client list. + protected void RemoveClient(Client client) { + Clients.Remove(client); + } + ///Returns the number of clients in the client list. + ///The number of connected clients. + public int GetClientCount() { + return Clients.Count; + } + ///Returns the requested client from the client list. + ///The index of the requested client. + ///The requested client. + ///If the specified index is invalid, the GetClientAt method returns null. + public Client GetClientAt(int Index) { + if (Index < 0 || Index >= GetClientCount()) + return null; + return (Client)Clients[Index]; + } + ///Gets a value indicating whether the Listener is currently listening or not. + ///A boolean that indicates whether the Listener is currently listening or not. + public bool Listening { + get { + return ListenSocket != null; + } + } + ///Disposes of the resources (other than memory) used by the Listener. + ///Stops listening and disposes all the client objects. Once disposed, this object should not be used anymore. + /// + public void Dispose() { + if (IsDisposed) + return; + while (Clients.Count > 0) { + ((Client)Clients[0]).Dispose(); + } + try { + ListenSocket.Shutdown(SocketShutdown.Both); + } catch {} + if (ListenSocket != null) + ListenSocket.Close(); + m_IsDisposed = true; + } + ///Finalizes the Listener. + ///The destructor calls the Dispose method. + ~Listener() { + Dispose(); + } + ///Returns an external IP address of this computer, if present. + ///Returns an external IP address of this computer; if this computer does not have an external IP address, it returns the first local IP address it can find. + ///If this computer does not have any configured IP address, this method returns the IP address 0.0.0.0. + public static IPAddress GetLocalExternalIP() { + try { + IPHostEntry he = Dns.GetHostEntry(Dns.GetHostName()); + for (int Cnt = 0; Cnt < he.AddressList.Length; Cnt++) { + if (IsRemoteIP(he.AddressList[Cnt])) + return he.AddressList[Cnt]; + } + return he.AddressList[0]; + } catch { + return IPAddress.Any; + } + } + ///Checks whether the specified IP address is a remote IP address or not. + ///The IP address to check. + ///True if the specified IP address is a remote address, false otherwise. + protected static bool IsRemoteIP(IPAddress IP) { + byte First = IP.GetAddressBytes()[0]; + byte Second = IP.GetAddressBytes()[1]; + //Not 10.x.x.x And Not 172.16.x.x <-> 172.31.x.x And Not 192.168.x.x + //And Not Any And Not Loopback And Not Broadcast + return (First != 10) && + (First != 172 || (Second < 16 || Second > 31)) && + (First != 192 || Second != 168) && + (!IP.Equals(IPAddress.Any)) && + (!IP.Equals(IPAddress.Loopback)) && + (!IP.Equals(IPAddress.Broadcast)); + } + ///Checks whether the specified IP address is a local IP address or not. + ///The IP address to check. + ///True if the specified IP address is a local address, false otherwise. + protected static bool IsLocalIP(IPAddress IP) { + byte First = IP.GetAddressBytes()[0]; + byte Second = IP.GetAddressBytes()[1]; + //10.x.x.x Or 172.16.x.x <-> 172.31.x.x Or 192.168.x.x + return (First == 10) || + (First == 172 && (Second >= 16 && Second <= 31)) || + (First == 192 && Second == 168); + } + ///Returns an internal IP address of this computer, if present. + ///Returns an internal IP address of this computer; if this computer does not have an internal IP address, it returns the first local IP address it can find. + ///If this computer does not have any configured IP address, this method returns the IP address 0.0.0.0. + public static IPAddress GetLocalInternalIP() { + try { + IPHostEntry he = Dns.GetHostEntry(Dns.GetHostName()); + for (int Cnt = 0; Cnt < he.AddressList.Length; Cnt++) { + if (IsLocalIP(he.AddressList[Cnt])) + return he.AddressList[Cnt]; + } + return he.AddressList[0]; + } catch { + return IPAddress.Any; + } + } + ///Called when there's an incoming client connection waiting to be accepted. + ///The result of the asynchronous operation. + public abstract void OnAccept(IAsyncResult ar); + ///Returns a string representation of this object. + ///A string with information about this object. + public override abstract string ToString(); + ///Returns a string that holds all the construction information for this object. + ///A string that holds all the construction information for this object. + public abstract string ConstructString {get;} + // private variables + /// Holds the value of the Port property. + private int m_Port; + /// Holds the value of the Address property. + private IPAddress m_Address; + /// Holds the value of the ListenSocket property. + private Socket m_ListenSocket; + /// Holds the value of the Clients property. + private ArrayList m_Clients = new ArrayList(); + /// Holds the value of the IsDisposed property. + private bool m_IsDisposed = false; +} + +} \ No newline at end of file diff --git a/ProxyServer/PortMapClient.cs b/ProxyServer/PortMapClient.cs new file mode 100644 index 0000000..438f26d --- /dev/null +++ b/ProxyServer/PortMapClient.cs @@ -0,0 +1,95 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; +using Org.Mentalis.Proxy; + +namespace Org.Mentalis.Proxy.PortMap { + +///Relays data between a remote host and a local client. +public sealed class PortMapClient : Client { + ///Initializes a new instance of the PortMapClient class. + ///The Socket connection between this proxy server and the local client. + ///The callback method to be called when this Client object disconnects from the local client and the remote server. + ///The IP EndPoint to send the incoming data to. + public PortMapClient(Socket ClientSocket, DestroyDelegate Destroyer, IPEndPoint MapTo) : base(ClientSocket, Destroyer) { + this.MapTo = MapTo; + } + ///Gets or sets the IP EndPoint to map all incoming traffic to. + ///An IPEndPoint that holds the IP address and port to use when redirecting incoming traffic. + ///The specified value is null. + ///An IP EndPoint specifying the host and port to map all incoming traffic to. + private IPEndPoint MapTo { + get { + return m_MapTo; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_MapTo = value; + } + } + ///Starts connecting to the remote host. + override public void StartHandshake() { + try { + DestinationSocket = new Socket(MapTo.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + DestinationSocket.BeginConnect(MapTo, new AsyncCallback(this.OnConnected), DestinationSocket); + } catch { + Dispose(); + } + } + ///Called when the socket is connected to the remote host. + ///When the socket is connected to the remote host, the PortMapClient begins relaying traffic between the host and the client, until one of them closes the connection. + ///The result of the asynchronous operation. + private void OnConnected(IAsyncResult ar) { + try { + DestinationSocket.EndConnect(ar); + StartRelay(); + } catch { + Dispose(); + } + } + ///Returns text information about this PortMapClient object. + ///A string representing this PortMapClient object. + public override string ToString() { + try { + return "Forwarding port from " + ((IPEndPoint)ClientSocket.RemoteEndPoint).Address.ToString() + " to " + MapTo.ToString(); + } catch { + return "Incoming Port forward connection"; + } + } + // private variables + /// Holds the value of the MapTo property. + private IPEndPoint m_MapTo; +} + +} diff --git a/ProxyServer/PortMapListener.cs b/ProxyServer/PortMapListener.cs new file mode 100644 index 0000000..51d95ac --- /dev/null +++ b/ProxyServer/PortMapListener.cs @@ -0,0 +1,115 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; +using Org.Mentalis.Proxy; + +namespace Org.Mentalis.Proxy.PortMap { + +///Listens on a specific port on the proxy server and forwards all incoming data to a specific port on another server. +public sealed class PortMapListener : Listener { + ///Initializes a new instance of the PortMapListener class. + ///The port to listen on. + ///The address to forward to. + ///The object will listen on all network addresses on the computer. + ///Port is not positive. + ///MapToIP is null. + public PortMapListener(int Port, IPEndPoint MapToIP) : this(IPAddress.Any, Port, MapToIP) {} + ///Initializes a new instance of the PortMapListener class. + ///The port to listen on. + ///The network address to listen on. + ///The address to forward to. + ///For security reasons, Address should not be IPAddress.Any. + ///Address or MapToIP is null. + ///Port is not positive. + public PortMapListener(IPAddress Address, int Port, IPEndPoint MapToIP) : base(Port, Address) { + MapTo = MapToIP; + } + ///Initializes a new instance of the PortMapListener class. + ///The port to listen on. + ///The network address to listen on. + ///The port to forward to. + ///The IP address to forward to. + ///For security reasons, Address should not be IPAddress.Any. + ///Address or MapToAddress is null. + ///Port or MapToPort is invalid. + public PortMapListener(IPAddress Address, int Port, IPAddress MapToAddress, int MapToPort) : this(Address, Port, new IPEndPoint(MapToAddress, MapToPort)) {} + ///Gets or sets the IP EndPoint to map all incoming traffic to. + ///An IPEndPoint that holds the IP address and port to use when redirecting incoming traffic. + ///The specified value is null. + ///An IP EndPoint specifying the host and port to map all incoming traffic to. + private IPEndPoint MapTo { + get { + return m_MapTo; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_MapTo = value; + } + } + ///Called when there's an incoming client connection waiting to be accepted. + ///The result of the asynchronous operation. + public override void OnAccept(IAsyncResult ar) { + try { + Socket NewSocket = ListenSocket.EndAccept(ar); + if (NewSocket != null) { + PortMapClient NewClient = new PortMapClient(NewSocket, new DestroyDelegate(this.RemoveClient), MapTo); + AddClient(NewClient); + NewClient.StartHandshake(); + } + } catch {} + try { + //Restart Listening + ListenSocket.BeginAccept(new AsyncCallback(this.OnAccept), ListenSocket); + } catch { + Dispose(); + } + } + ///Returns a string representation of this object. + ///A string with information about this object. + public override string ToString() { + return "PORTMAP service on " + Address.ToString() + ":" + Port.ToString(); + } + ///Returns a string that holds all the construction information for this object. + ///A string that holds all the construction information for this object. + public override string ConstructString { + get { + return "host:" + Address.ToString() + ";int:" + Port.ToString() + ";host:" + MapTo.Address.ToString() + ";int:" + MapTo.Port.ToString(); + } + } + // private variables + /// Holds the value of the MapTo property. + private IPEndPoint m_MapTo; +} + +} diff --git a/ProxyServer/Proxy.cs b/ProxyServer/Proxy.cs new file mode 100644 index 0000000..5d4bcd2 --- /dev/null +++ b/ProxyServer/Proxy.cs @@ -0,0 +1,429 @@ +/* + Copyright ?2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.IO; +using System.Net; +using System.Text; +using System.Threading; +using System.Reflection; +using System.Collections; +using System.Net.Sockets; +using System.Security.Cryptography; +using System.Globalization; +using Org.Mentalis.Proxy; +using Org.Mentalis.Proxy.Ftp; +using Org.Mentalis.Proxy.Http; +using Org.Mentalis.Proxy.Socks; +using Org.Mentalis.Proxy.PortMap; +using Org.Mentalis.Proxy.Socks.Authentication; +using Org.Mentalis.Utilities.ConsoleAttributes; + +namespace Org.Mentalis.Proxy { + /// + /// Represents an item in a Listeners collection. + /// + public struct ListenEntry { + /// + /// The Listener object. + /// + public Listener listener; + /// + /// The Listener's ID. It must be unique troughout the Listeners collection. + /// + public Guid guid; + /// + /// Determines whether the specified Object is equal to the current Object. + /// + /// The Object to compare with the current Object. + /// True if the specified Object is equal to the current Object; otherwise, false. + public override bool Equals(object obj) { + return ((ListenEntry)obj).guid.Equals(guid); + } + + /// + /// + /// + public override int GetHashCode() + { + return guid.GetHashCode(); + } + + } + /// + /// Defines the class that controls the settings and listener objects. + /// + public class Proxy { + /// + /// Entry point of the application. + /// + public static void Main() { + try { + string dir = Environment.CurrentDirectory; + if (!dir.Substring(dir.Length - 1, 1).Equals(@"\")) + dir += @"\"; + Proxy prx = new Proxy(dir + "config.xml"); + prx.Start(); + } catch { + Console.WriteLine("The program ended abnormally!"); + } + } + /// + /// Initializes a new Proxy instance. + /// + /// The XML configuration file to use. + public Proxy(string file) { + Config = new ProxyConfig(this, file); + } + /// + /// Starts a new Proxy server by reading the data from the configuration file and start listening on the specified ports. + /// + public void Start() { + // Initialize some objects + StartTime = DateTime.Now; + if (System.IO.File.Exists(Config.File)) + Config.LoadData(); + // Start the proxy + string command; + Console.WriteLine("\r\n Mentalis.org Proxy\r\n ~~~~~~~~~~~~~~~~~~\r\n\r\n (type 'help' for the command list)"); + Console.Write("\r\n>"); + command = Console.ReadLine().ToLower(CultureInfo.InvariantCulture); + while (!command.Equals("exit")) { + switch(command) { + case "help": + ShowHelp(); + break; + case "uptime": + ShowUpTime(); + break; + case "version": + ShowVersion(); + break; + case "adduser": + ShowAddUser(); + break; + case "deluser": + ShowDelUser(); + break; + case "listusers": + ShowUsers(); + break; + case "addlistener": + ShowAddListener(); + break; + case "listlisteners": + ShowListeners(); + break; + case "dellistener": + ShowDelListener(); + break; + default: + Console.WriteLine("Command not understood."); + break; + } + Console.Write("\r\n>"); + command = Console.ReadLine().ToLower(CultureInfo.InvariantCulture); + } + Stop(); + Console.WriteLine("Goodbye..."); + } + /// + /// Asks the user which listener to delete. + /// + protected void ShowDelListener() { + Console.WriteLine("Please enter the ID of the listener you want to delete:\r\n (use the 'listlisteners' command to show all the listener IDs)"); + string id = Console.ReadLine(); + if (id != "") { + try { + ListenEntry le = new ListenEntry(); + le.guid = new Guid(id); + if (!Listeners.Contains(le)) { + Console.WriteLine("Specified ID not found in list!"); + return; + } else { + this[Listeners.IndexOf(le)].Dispose(); + Listeners.Remove(le); + Config.SaveData(); + } + } catch { + Console.WriteLine("Invalid ID tag!"); + return; + } + Console.WriteLine("Listener removed from the list."); + } + } + /// + /// Shows the Listeners list. + /// + protected void ShowListeners() { + for(int i = 0; i < Listeners.Count; i++) { + Console.WriteLine(((ListenEntry)Listeners[i]).listener.ToString()); + Console.WriteLine(" id: " + ((ListenEntry)Listeners[i]).guid.ToString("N")); + } + } + /// + /// Asks the user which listener to add. + /// + protected void ShowAddListener() { + Console.WriteLine("Please enter the full class name of the Listener object you're trying to add:\r\n (ie. Org.Mentalis.Proxy.Http.HttpListener)"); + string classtype = Console.ReadLine(); + if (classtype == "") + return; + else if(Type.GetType(classtype) == null) { + Console.WriteLine("The specified class does not exist!"); + return; + } + Console.WriteLine("Please enter the construction parameters:"); + string construct = Console.ReadLine(); + object listenObject = CreateListener(classtype, construct); + if (listenObject == null) { + Console.WriteLine("Invalid construction string."); + return; + } + Listener listener; + try { + listener = (Listener)listenObject; + } catch { + Console.WriteLine("The specified object is not a valid Listener object."); + return; + } + try { + listener.Start(); + AddListener(listener); + } catch { + Console.WriteLine("Error while staring the Listener.\r\n(Perhaps the specified port is already in use?)"); + return; + } + Config.SaveData(); + } + /// + /// Shows a list of commands in the console. + /// + protected void ShowHelp() { + Console.WriteLine(" help - Shows this help message\r\n uptime - Shows the uptime of the proxy server\r\n version - Prints the version of this program\r\n listusers - Lists all users\r\n adduser - Adds a user to the user list\r\n deluser - Deletes a user from the user list\r\n listlisteners - Lists all the listeners\r\n addlistener - Adds a new listener\r\n dellistener - Deletes a listener\r\n\r\n Read the readme.txt file for more help."); + } + /// + /// Shows the uptime of this proxy server. + /// + protected void ShowUpTime() { + TimeSpan uptime = DateTime.Now.Subtract(StartTime); + Console.WriteLine("Up " + uptime.ToString()); + } + /// + /// Shows the version number of this proxy server. + /// + protected void ShowVersion() { + Console.WriteLine("This is version " + Assembly.GetCallingAssembly().GetName().Version.ToString(3) + " of the Mentalis.org proxy server."); + } + /// + /// Asks the user which username to add. + /// + protected void ShowAddUser() { + Console.Write("Please enter the username to add: "); + string name = Console.ReadLine(); + if (Config.UserList.IsUserPresent(name)) { + Console.WriteLine("Username already exists in database."); + return; + } + Console.Write("Please enter the password: "); + ConsoleAttributes.EchoInput = false; + string pass1 = Console.ReadLine(); + Console.Write("\r\nPlease enter the password again: "); + string pass2 = Console.ReadLine(); + ConsoleAttributes.EchoInput = true; + if (!pass1.Equals(pass2)) { + Console.WriteLine("\r\nThe passwords do not match."); + return; + } + Config.SaveUserPass(name, pass1); + Console.WriteLine("\r\nUser successfully added."); + } + /// + /// Asks the user which username to delete. + /// + protected void ShowDelUser() { + Console.Write("Please enter the username to remove: "); + string name = Console.ReadLine(); + if (!Config.UserList.IsUserPresent(name)) { + Console.WriteLine("Username not present in database."); + return; + } + Config.RemoveUser(name); + Console.WriteLine("User '" + name + "' successfully removed."); + } + /// + /// Shows a list of usernames in the console. + /// + protected void ShowUsers() { + if (Config.UserList == null || Config.UserList.Keys.Length == 0) { + Console.WriteLine("There are no users in the user list."); + } else { + Console.WriteLine("The following " + Config.UserList.Keys.Length.ToString() + " users are allowed to use the SOCKS5 proxy:"); + Console.WriteLine(string.Join(", ", Config.UserList.Keys)); + } + } + /// + /// Stops the proxy server. + /// + /// When this method is called, all listener and client objects will be disposed. + public void Stop() { + // Stop listening and clear the Listener list + for (int i = 0; i < ListenerCount; i++) { + Console.WriteLine(this[i].ToString() + " stopped."); + this[i].Dispose(); + } + Listeners.Clear(); + } + /// + /// Adds a listener to the Listeners list. + /// + /// The new Listener to add. + public void AddListener(Listener newItem) { + if (newItem == null) + throw new ArgumentNullException(); + ListenEntry le = new ListenEntry(); + le.listener = newItem; + le.guid = Guid.NewGuid(); + while (Listeners.Contains(le)) { + le.guid = Guid.NewGuid(); + } + Listeners.Add(le); + Console.WriteLine(newItem.ToString() + " started."); + } + /// + /// Creates a new Listener obejct from a given listener name and a given listener parameter string. + /// + /// The type of object to instantiate. + /// + /// + public Listener CreateListener(string type, string cpars) { + try { + string [] parts = cpars.Split(';'); + object [] pars = new object[parts.Length]; + string oval = null, otype = null; + int ret; + // Start instantiating the objects to give to the constructor + for(int i = 0; i < parts.Length; i++) { + ret = parts[i].IndexOf(':'); + if (ret >= 0) { + otype = parts[i].Substring(0, ret); + oval = parts[i].Substring(ret + 1); + } else { + otype = parts[i]; + } + switch (otype.ToLower(CultureInfo.InvariantCulture)) { + case "int": + pars[i] = int.Parse(oval); + break; + case "host": + pars[i] = Dns.GetHostEntry(oval).AddressList[0]; + break; + case "authlist": + pars[i] = Config.UserList; + break; + case "null": + pars[i] = null; + break; + case "string": + pars[i] = oval; + break; + case "ip": + pars[i] = IPAddress.Parse(oval); + break; + default: + pars[i] = null; + break; + } + } + return (Listener)Activator.CreateInstance(Type.GetType(type), pars); + } catch { + return null; + } + } + /// + /// Gets the collection that contains all the Listener objects. + /// + /// An ArrayList object that contains all the Listener objects. + protected ArrayList Listeners { + get { + return m_Listeners; + } + } + /// + /// Gets the number of Listener objects. + /// + /// An integer specifying the number of Listener objects. + internal int ListenerCount { + get { + return Listeners.Count; + } + } + /// + /// Gets the Listener object at the specified position. + /// + /// The Listener instance at position index. + internal virtual Listener this[int index] { + get { + return ((ListenEntry)Listeners[index]).listener; + } + } + /// + /// Gets or sets the date when this Proxy server was first started. + /// + /// A DateTime structure that indicates when this Proxy server was first started. + protected DateTime StartTime { + get { + return m_StartTime; + } + set { + m_StartTime = value; + } + } + /// + /// Gets or sets the configuration object for this Proxy server. + /// + /// A ProxyConfig instance that represents the configuration object for this Proxy server. + protected ProxyConfig Config { + get { + return m_Config; + } + set { + m_Config = value; + } + } + // private variables + /// Holds the value of the StartTime property. + private DateTime m_StartTime; + /// Holds the value of the Config property. + private ProxyConfig m_Config; + /// Holds the value of the Listeners property. + private ArrayList m_Listeners = new ArrayList(); + } +} diff --git a/ProxyServer/ProxyConfig.cs b/ProxyServer/ProxyConfig.cs new file mode 100644 index 0000000..be8ed9d --- /dev/null +++ b/ProxyServer/ProxyConfig.cs @@ -0,0 +1,488 @@ +/* + Copyright ?2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.IO; +using System.Xml; +using System.Text; +using System.Collections; +using System.Collections.Specialized; +using System.Security.Cryptography; +using System.Reflection; +using System.Reflection.Emit; +using System.Net; +using Org.Mentalis.Proxy; +using Org.Mentalis.Proxy.Socks.Authentication; +using System.Globalization; + +namespace Org.Mentalis.Proxy { + /// + /// Stores the configuration settings of this proxy server. + /// + public sealed class ProxyConfig { + /// + /// Initializes a new ProxyConfig instance. + /// + /// The parent of this ProxyCondif instance. + /// The XML file to read data from and store data to. + /// file is null -or- parent is null. + public ProxyConfig(Proxy parent, string file) { + if (file == null || parent == null) + throw new ArgumentNullException(); + m_File = file; + m_Parent = parent; + } + /// + /// Reads a string from the settings section. + /// + /// The key to read from. + /// The string value that corresponds with the specified key, or an empty string if the specified key was not found in the collection. + public string ReadString(string name) { + return ReadString(name, ""); + } + /// + /// Reads a string from the settings section. + /// + /// The key to read from. + /// The default string to return. + /// The string value that corresponds with the specified key, or def if the specified key was not found in the collection. + public string ReadString(string name, string def) { + if (name == null) + return def; + if (!Settings.ContainsKey(name)) + return def; + return Settings[name]; + } + /// + /// Reads a byte array from the settings section. + /// + /// The key to read from. + /// The array of bytes that corresponds with the specified key, or null if the specified key was not found in the collection. + public byte[] ReadBytes(string name) { + string ret = ReadString(name, null); + if (ret == null) + return null; + return Convert.FromBase64String(ret); + } + /// + /// Reads an integer from the settings section. + /// + /// The key to read from. + /// The integer that corresponds with the specified key, or 0 if the specified key was not found in the collection. + public int ReadInt(string name) { + return ReadInt(name, 0); + } + /// + /// Reads an integer from the settings section. + /// + /// The key to read from. + /// The default integer to return. + /// The integer that corresponds with the specified key, or def if the specified key was not found in the collection. + public int ReadInt(string name, int def) { + if (name == null) + return def; + if (!Settings.ContainsKey(name)) + return def; + return int.Parse(Settings[name]); + } + /// + /// Saves a string to the settings section. + /// + /// The key of the setting. + /// The string data of the setting. + public void SaveSetting(string name, string data) { + SaveSetting(name, data, true); + } + /// + /// Saves a string to the settings section. + /// + /// The key of the setting. + /// The string data of the setting. + /// True if the data has to be written to the XML file, false otherwise. + public void SaveSetting(string name, string data, bool saveData) { + if (name == null || data == null) + throw new ArgumentNullException(); + if (Settings.ContainsKey(name)) + Settings[name] = data; + else + Settings.Add(name, data); + if (saveData) + SaveData(); + } + /// + /// Saves an integer to the settings section. + /// + /// The key of the setting. + /// The integer data of the setting. + public void SaveSetting(string name, int data) { + SaveSetting(name, data, true); + } + /// + /// Saves an integer to the settings section. + /// + /// The key of the setting. + /// The integer data of the setting. + /// True if the data has to be written to the XML file, false otherwise. + public void SaveSetting(string name, int data, bool saveData) { + SaveSetting(name, data.ToString(), saveData); + } + /// + /// Saves an array of bytes to the settings section. + /// + /// The key of the setting. + /// The byte data of the setting. + public void SaveSetting(string name, byte [] data) { + SaveSetting(name, data, true); + } + /// + /// Saves an array of bytes to the settings section. + /// + /// The key of the setting. + /// The byte data of the setting. + /// True if the data has to be written to the XML file, false otherwise. + public void SaveSetting(string name, byte [] data, bool saveData) { + if (data == null) + throw new ArgumentNullException(); + SaveSetting(name, Convert.ToBase64String(data), saveData); + } + /// + /// Saves a username and password combination to the authentication list. + /// + /// The username to add. + /// The password to add. + /// username is null -or- password is null. + /// The specified username is invalid. + ///

If the user already exists in the collection, the old password will be changed to the new one.

The username 'users' is invalid because it is used internally to store the usernames.

+ public void SaveUserPass(string username, string password) { + SaveUserPass(username, password, true); + } + /// + /// Saves a username and password combination to the authentication list. + /// + /// The username to add. + /// The password to add. + /// True if the data has to be written to the XML file, false otherwise. + /// username is null -or- password is null. + /// The specified username is invalid. + ///

If the user already exists in the collection, the old password will be changed to the new one.

The username 'users' is invalid because it is used internally to store the usernames.

The password will be hashed before it is stored in the authentication list.

+ public void SaveUserPass(string username, string password, bool saveData) { + if (username == null || password == null) + throw new ArgumentNullException(); + if (username.ToLower(CultureInfo.InvariantCulture) == "users" || username == "") + throw new ArgumentException(); + if (UserList.IsUserPresent(username)) + UserList.RemoveItem(username); + UserList.AddItem(username, password); + if (saveData) + SaveData(); + } + /// + /// Saves a username and password hash combination to the authentication list. + /// + /// The username to add. + /// The password hash to add. + /// username is null -or- passHash is null. + /// The specified username is invalid. + ///

If the user already exists in the collection, the old password hash will be changed to the new one.

The username 'users' is invalid because it is used internally to store the usernames.

The password will not be hashed before it is stored in the authentication list. The user must make sure it is a valid MD5 hash.

+ public void SaveUserHash(string username, string passHash) { + SaveUserHash(username, passHash, true); + } + /// + /// Saves a username and password hash combination to the authentication list. + /// + /// The username to add. + /// The password hash to add. + /// True if the data has to be written to the XML file, false otherwise. + /// username is null -or- passHash is null. + /// The specified username is invalid. + ///

If the user already exists in the collection, the old password hash will be changed to the new one.

The username 'users' is invalid because it is used internally to store the usernames.

The password will not be hashed before it is stored in the authentication list. The user must make sure it is a valid MD5 hash.

+ public void SaveUserHash(string username, string passHash, bool saveData) { + if (username == null || passHash == null) + throw new ArgumentNullException(); + if (username.ToLower(CultureInfo.InvariantCulture) == "users" || username == "") + throw new ArgumentException(); + UserList.AddHash(username, passHash); + if (saveData) + SaveData(); + } + /// + /// Removes a user from the authentication list. + /// + /// The user to remove. + public void RemoveUser(string user) { + RemoveUser(user, true); + } + /// + /// Removes a user from the authentication list. + /// + /// The user to remove. + /// True if the data has to be written to the XML file, false otherwise. + public void RemoveUser(string user, bool save) { + if (user == null) + throw new ArgumentNullException(); + UserList.RemoveItem(user); + if (save) + SaveData(); + } + /// + /// Saves the data in this class to an XML file. + /// + public void SaveData() { + XmlTextWriter writer = null; + try { + writer = new XmlTextWriter(File, Encoding.ASCII); + writer.Indentation = 2; + writer.Formatting = Formatting.Indented; + writer.WriteStartElement("MentalisProxy"); + // Write the version + writer.WriteStartElement("Version"); + writer.WriteStartAttribute("", "value", ""); + writer.WriteString(Assembly.GetCallingAssembly().GetName().Version.ToString(2)); + writer.WriteEndAttribute(); + writer.WriteEndElement(); + // Write the settings + SaveSettings(writer); + // Write the Authentication list to the file + SaveUsers(writer); + // Write the Listeners list to the file + SaveListeners(writer); + // Clean up + writer.WriteEndElement(); + } catch { + } finally { + if (writer != null) + writer.Close(); + } + } + /// + /// Saves the settings in this class to an XML writer. + /// + /// The XML writer to save the data to. + private void SaveSettings(XmlTextWriter writer) { + writer.WriteStartElement("Settings"); + string [] keys = new string[Settings.Count]; + Settings.Keys.CopyTo(keys, 0); + for (int i = 0; i < keys.Length; i++) { + writer.WriteStartElement(keys[i]); + writer.WriteStartAttribute("", "value", ""); + writer.WriteString(Settings[keys[i]]); + writer.WriteEndAttribute(); + writer.WriteEndElement(); + } + writer.WriteEndElement(); + } + /// + /// Saves the authentication list to an XML writer. + /// + /// The XML writer to save the users to. + private void SaveUsers(XmlTextWriter writer) { + writer.WriteStartElement("Users"); + string [] keys = UserList.Keys; + string [] hashes = UserList.Hashes; + for (int i = 0; i < keys.Length; i++) { + writer.WriteStartElement(keys[i]); + writer.WriteStartAttribute("", "value", ""); + writer.WriteString(hashes[i]); + writer.WriteEndAttribute(); + writer.WriteEndElement(); + } + writer.WriteEndElement(); + } + /// + /// Saves the listeners to an XML writer. + /// + /// The XML writer to save the users to. + private void SaveListeners(XmlTextWriter writer) { + writer.WriteStartElement("Listeners"); + lock (Parent) { + for (int i = 0; i < Parent.ListenerCount; i++) { + writer.WriteStartElement("listener"); + // Write the type, eg 'Org.Mentalis.Proxy.Http.HttpListener' + writer.WriteStartAttribute("", "type", ""); + writer.WriteString(Parent[i].GetType().FullName); + writer.WriteEndAttribute(); + // Write the construction string + writer.WriteStartAttribute("", "value", ""); + writer.WriteString(Parent[i].ConstructString); + writer.WriteEndAttribute(); + writer.WriteEndElement(); + } + } + writer.WriteEndElement(); + } + /// + /// Loads the data from an XML file. + /// + public void LoadData() { + if (!System.IO.File.Exists(File)) + throw new FileNotFoundException(); + XmlTextReader reader = null; + try { + reader = new XmlTextReader(File); + // Read until we reach the MentalisProxy element + while (reader.Read() && reader.Name.ToLower(CultureInfo.InvariantCulture) != "mentalisproxy") {} + // Read until we reach the MentalisProxy element again (the end tag) + while (reader.Read() && reader.Name.ToLower(CultureInfo.InvariantCulture) != "mentalisproxy") { + if (!reader.IsEmptyElement) { + switch(reader.Name.ToLower(CultureInfo.InvariantCulture)) { + case "settings": + Settings.Clear(); + LoadSettings(reader); + break; + case "users": + UserList.Clear(); + LoadUsers(reader); + break; + case "listeners": + LoadListeners(reader); + break; + } + } + } + } catch { + throw new XmlException ("Malformed XML initialisation file.", null); + } finally { + if (reader != null) + reader.Close(); + } + } + /// + /// Loads the settings from an XML file. + /// + /// The XML reader to read the settings from. + private void LoadSettings(XmlTextReader reader) { + // Read until we reach the Settings element end tag + while (reader.Read() && reader.Name.ToLower(CultureInfo.InvariantCulture) != "settings") { + if (reader.Name != null && reader["value"] != null) + SaveSetting(reader.Name, reader["value"], false); + } + } + /// + /// Loads the userlist from an XML file. + /// + /// The XML reader to read the users from. + private void LoadUsers(XmlTextReader reader) { + // Read until we reach the Settings element end tag + while (reader.Read() && reader.Name.ToLower(CultureInfo.InvariantCulture) != "users") { + if (reader.Name != null && reader["value"] != null) + SaveUserHash(reader.Name, reader["value"], false); + } + } + /// + /// Loads the listeners list from an XML file. + /// + /// The XML reader to read the users from. + private void LoadListeners(XmlTextReader reader) { + // Read until we reach the Listeners element end tag + Listener listener = null; + while (reader.Read() && reader.Name.ToLower(CultureInfo.InvariantCulture) != "listeners") { + if (reader.Name != null && reader["value"] != null && reader["type"] != null) { + listener = Parent.CreateListener(reader["type"], reader["value"]); + if (listener != null) { + try { + listener.Start(); + } catch {} + Parent.AddListener(listener); + } + } + } + } + /// + /// Gets the full path to the XML data file. + /// + /// A String that holds the full path to the XML data file. + public string File { + get { + return m_File; + } + } + /// + /// Gets the parent object of this ProxyConfig class. + /// + /// An instance of the Proxy class. + public Proxy Parent { + get { + return m_Parent; + } + } + /// + /// Gets the dictionary that holds the settings. + /// + /// An instance of the StringDictionary class that holds the settings. + private StringDictionary Settings { + get { + return m_Settings; + } + } + /// + /// Gets the userlist. + /// + /// An instance of the AuthenticationList class that holds all the users and their corresponding password hashes. + internal AuthenticationList UserList { + get { + return m_UserList; + } + } + // private variables + /// Holds the value of the File property. + private string m_File; + /// Holds the value of the Settings property. + private StringDictionary m_Settings = new StringDictionary(); + /// Holds the value of the UserList property. + private AuthenticationList m_UserList = new AuthenticationList(); + /// Holds the value of the Parent property. + private Proxy m_Parent; + } + +} + +/* + + + + + + + + + + + + + + + + + + + + + +*/ diff --git a/ProxyServer/ProxyServer.csproj b/ProxyServer/ProxyServer.csproj new file mode 100644 index 0000000..57d426d --- /dev/null +++ b/ProxyServer/ProxyServer.csproj @@ -0,0 +1,180 @@ + + + + Local + 8.0.50727 + 2.0 + {EB773C85-DDF7-4031-A993-102B9C8ED02C} + Debug + AnyCPU + + + ProxyServer + JScript + Grid + IE50 + false + Library + ProxyServer + OnBuildSuccess + + + + + v2.0 + 2.0 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + bin\Debug\ + 285212672 + + + DEBUG;TRACE + + + true + 4096 + false + false + false + 4 + full + prompt + AllRules.ruleset + + + bin\Release\ + 285212672 + + + TRACE + + + 4096 + true + false + false + 4 + none + prompt + AllRules.ruleset + + + + System + + + System.Data + + + System.XML + + + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + + + + + + \ No newline at end of file diff --git a/ProxyServer/ProxyServer.csproj.user b/ProxyServer/ProxyServer.csproj.user new file mode 100644 index 0000000..6f23531 --- /dev/null +++ b/ProxyServer/ProxyServer.csproj.user @@ -0,0 +1,13 @@ + + + + + + + + + + en-US + false + + \ No newline at end of file diff --git a/ProxyServer/Socks4Handler.cs b/ProxyServer/Socks4Handler.cs new file mode 100644 index 0000000..4cba38c --- /dev/null +++ b/ProxyServer/Socks4Handler.cs @@ -0,0 +1,151 @@ +/* + Copyright ?2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Text; +using System.Net; +using System.Net.Sockets; +using Org.Mentalis.Proxy; + +namespace Org.Mentalis.Proxy.Socks { + +///Implements the SOCKS4 and SOCKS4a protocols. +internal sealed class Socks4Handler : SocksHandler { + ///Initializes a new instance of the Socks4Handler class. + ///The connection with the client. + ///The method to call when the SOCKS negotiation is complete. + ///Callback is null. + public Socks4Handler(Socket ClientConnection, NegotiationCompleteDelegate Callback) : base(ClientConnection, Callback) {} + ///Checks whether a specific request is a valid SOCKS request or not. + ///The request array to check. + ///True is the specified request is valid, false otherwise + protected override bool IsValidRequest(byte [] Request) { + try { + if (Request[0] != 1 && Request[0] != 2) { //CONNECT or BIND + Dispose(false); + } else { + if (Request[3] == 0 && Request[4] == 0 && Request[5] == 0 && Request[6] != 0) { //Use remote DNS + int Ret = Array.IndexOf(Request, (byte)0, 7); + if (Ret > -1) + return Array.IndexOf(Request, (byte)0, Ret + 1) != -1; + } else { + return Array.IndexOf(Request, (byte)0, 7) != -1; + } + } + } catch {} + return false; + } + ///Processes a SOCKS request from a client. + ///The request to process. + protected override void ProcessRequest(byte [] Request) { + int Ret; + try { + if (Request[0] == 1) { // CONNECT + IPAddress RemoteIP; + int RemotePort = Request[1] * 256 + Request[2]; + Ret = Array.IndexOf(Request, (byte)0, 7); + Username = Encoding.ASCII.GetString(Request, 7, Ret - 7); + if (Request[3] == 0 && Request[4] == 0 && Request[5] == 0 && Request[6] != 0) {// Use remote DNS + Ret = Array.IndexOf(Request, (byte)0, Ret + 1); + RemoteIP = Dns.GetHostEntry(Encoding.ASCII.GetString(Request, Username.Length + 8, Ret - Username.Length - 8)).AddressList[0]; + } else { //Do not use remote DNS + RemoteIP = IPAddress.Parse(Request[3].ToString() + "." + Request[4].ToString() + "." + Request[5].ToString() + "." + Request[6].ToString()); + } + RemoteConnection = new Socket(RemoteIP.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + RemoteConnection.BeginConnect(new IPEndPoint(RemoteIP, RemotePort), new AsyncCallback(this.OnConnected), RemoteConnection); + } else if (Request[0] == 2) { // BIND + byte[] Reply = new byte[8]; + byte[] LocalIP = Listener.GetLocalExternalIP().GetAddressBytes(); + AcceptSocket = new Socket(IPAddress.Any.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + AcceptSocket.Bind(new IPEndPoint(IPAddress.Any, 0)); + AcceptSocket.Listen(50); + RemoteBindIP = IPAddress.Parse(Request[3].ToString() + "." + Request[4].ToString() + "." + Request[5].ToString() + "." + Request[6].ToString()); + Reply[0] = 0; //Reply version 0 + Reply[1] = 90; //Everything is ok :) + Reply[2] = (byte)(Math.Floor((double)((IPEndPoint)AcceptSocket.LocalEndPoint).Port / 256)); //Port/1 + Reply[3] = (byte)(((IPEndPoint)AcceptSocket.LocalEndPoint).Port % 256); //Port/2 + Reply[4] = LocalIP[0];// (byte)(Math.Floor((double)(LocalIP % 256))); //IP Address/1 + Reply[5] = LocalIP[1];// (byte)(Math.Floor((double)(LocalIP % 65536) / 256)); //IP Address/2 + Reply[6] = LocalIP[2];// (byte)(Math.Floor((double)(LocalIP % 16777216) / 65536)); //IP Address/3 + Reply[7] = LocalIP[3];// (byte)(Math.Floor((double)LocalIP / 16777216)); //IP Address/4 + Connection.BeginSend(Reply, 0, Reply.Length, SocketFlags.None, new AsyncCallback(this.OnStartAccept), Connection); + } + } catch { + Dispose(91); + } + } + ///Called when we're successfully connected to the remote host. + ///The result of the asynchronous operation. + private void OnConnected(IAsyncResult ar) { + try { + RemoteConnection.EndConnect(ar); + Dispose(90); + } catch { + Dispose(91); + } + } + ///Sends a reply to the client connection and disposes it afterwards. + ///A byte that contains the reply code to send to the client. + protected override void Dispose(byte Value) { + byte [] ToSend; + try { + ToSend = new byte[]{0, Value, (byte)(Math.Floor((double)((IPEndPoint)RemoteConnection.RemoteEndPoint).Port / 256)), + (byte)(((IPEndPoint)RemoteConnection.RemoteEndPoint).Port % 256), + ((IPEndPoint)RemoteConnection.RemoteEndPoint).Address.GetAddressBytes()[0], + ((IPEndPoint)RemoteConnection.RemoteEndPoint).Address.GetAddressBytes()[1], + ((IPEndPoint)RemoteConnection.RemoteEndPoint).Address.GetAddressBytes()[2], + ((IPEndPoint)RemoteConnection.RemoteEndPoint).Address.GetAddressBytes()[3]}; + } catch { + ToSend = new byte[]{0, 91, 0, 0, 0, 0, 0, 0}; + } + try { + Connection.BeginSend(ToSend, 0, ToSend.Length, SocketFlags.None, (AsyncCallback)(ToSend[1] == 90 ? new AsyncCallback(this.OnDisposeGood) : new AsyncCallback(this.OnDisposeBad)), Connection); + } catch { + Dispose(false); + } + } + ///Called when there's an incoming connection in the AcceptSocket queue. + ///The result of the asynchronous operation. + protected override void OnAccept(IAsyncResult ar) { + try { + RemoteConnection = AcceptSocket.EndAccept(ar); + AcceptSocket.Close(); + AcceptSocket = null; + if (RemoteBindIP.Equals(((IPEndPoint)RemoteConnection.RemoteEndPoint).Address)) + Dispose(90); + else + Dispose(91); + } catch { + Dispose(91); + } + } +} + +} diff --git a/ProxyServer/Socks5Handler.cs b/ProxyServer/Socks5Handler.cs new file mode 100644 index 0000000..a7a7ec2 --- /dev/null +++ b/ProxyServer/Socks5Handler.cs @@ -0,0 +1,277 @@ +/* + Copyright ?2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; +using Org.Mentalis.Proxy; +using Org.Mentalis.Proxy.Socks.Authentication; + +namespace Org.Mentalis.Proxy.Socks { + +///Implements the SOCKS5 protocol. +internal sealed class Socks5Handler : SocksHandler { + ///Initializes a new instance of the Socks5Handler class. + ///The connection with the client. + ///The method to call when the SOCKS negotiation is complete. + ///The authentication list to use when clients connect. + ///Callback is null. + ///If the AuthList parameter is null, no authentication will be required when a client connects to the proxy server. + public Socks5Handler(Socket ClientConnection, NegotiationCompleteDelegate Callback, AuthenticationList AuthList) : base(ClientConnection, Callback) { + this.AuthList = AuthList; + } + ///Initializes a new instance of the Socks5Handler class. + ///The connection with the client. + ///The method to call when the SOCKS negotiation is complete. + ///Callback is null. + public Socks5Handler(Socket ClientConnection, NegotiationCompleteDelegate Callback) : this(ClientConnection, Callback, null) {} + ///Checks whether a specific request is a valid SOCKS request or not. + ///The request array to check. + ///True is the specified request is valid, false otherwise + protected override bool IsValidRequest(byte [] Request) { + try { + return (Request.Length == Request[0] + 1); + } catch { + return false; + } + } + ///Processes a SOCKS request from a client and selects an authentication method. + ///The request to process. + protected override void ProcessRequest(byte [] Request) { + try { + byte Ret = 255; + for (int Cnt = 1; Cnt < Request.Length; Cnt++) { + if (Request[Cnt] == 0 && AuthList == null) { //0 = No authentication + Ret = 0; + AuthMethod = new AuthNone(); + break; + } else if (Request[Cnt] == 2 && AuthList != null) { //2 = user/pass + Ret = 2; + AuthMethod = new AuthUserPass(AuthList); + if (AuthList != null) + break; + } + } + Connection.BeginSend(new byte[]{5, Ret}, 0, 2, SocketFlags.None, new AsyncCallback(this.OnAuthSent), Connection); + } catch { + Dispose(false); + } + } + ///Called when client has been notified of the selected authentication method. + ///The result of the asynchronous operation. + private void OnAuthSent(IAsyncResult ar) { + try { + if (Connection.EndSend(ar) <= 0 || AuthMethod == null) { + Dispose(false); + return; + } + AuthMethod.StartAuthentication(Connection, new AuthenticationCompleteDelegate(this.OnAuthenticationComplete)); + } catch { + Dispose(false); + } + } + ///Called when the authentication is complete. + ///Indicates whether the authentication was successful ot not. + private void OnAuthenticationComplete(bool Success) { + try { + if (Success) { + Bytes = null; + Connection.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnRecvRequest), Connection); + } else { + Dispose(false); + } + } catch { + Dispose(false); + } + } + ///Called when we received the request of the client. + ///The result of the asynchronous operation. + private void OnRecvRequest(IAsyncResult ar) { + try { + int Ret = Connection.EndReceive(ar); + if (Ret <= 0) { + Dispose(false); + return; + } + AddBytes(Buffer, Ret); + if (IsValidQuery(Bytes)) + ProcessQuery(Bytes); + else + Connection.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnRecvRequest), Connection); + } catch { + Dispose(false); + } + } + ///Checks whether a specified query is a valid query or not. + ///The query to check. + ///True if the query is valid, false otherwise. + private bool IsValidQuery(byte [] Query) { + try { + switch(Query[3]) { + case 1: //IPv4 address + return (Query.Length == 10); + case 3: //Domain name + return (Query.Length == Query[4] + 7); + case 4: //IPv6 address + //Not supported + Dispose(8); + return false; + default: + Dispose(false); + return false; + } + } catch { + return false; + } + } + ///Processes a received query. + ///The query to process. + private void ProcessQuery(byte [] Query) { + try { + switch(Query[1]) { + case 1: //CONNECT + IPAddress RemoteIP = null; + int RemotePort = 0; + if (Query[3] == 1) { + RemoteIP = IPAddress.Parse(Query[4].ToString() + "." + Query[5].ToString() + "." + Query[6].ToString() + "." + Query[7].ToString()); + RemotePort = Query[8] * 256 + Query[9]; + } else if( Query[3] == 3) { + RemoteIP = Dns.GetHostEntry(Encoding.ASCII.GetString(Query, 5, Query[4])).AddressList[0]; + RemotePort = Query[4] + 5; + RemotePort = Query[RemotePort] * 256 + Query[RemotePort + 1]; + } + RemoteConnection = new Socket(RemoteIP.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + RemoteConnection.BeginConnect(new IPEndPoint(RemoteIP, RemotePort), new AsyncCallback(this.OnConnected), RemoteConnection); + break; + case 2: //BIND + byte[] Reply = new byte[10]; + byte[] LocalIP = Listener.GetLocalExternalIP().GetAddressBytes(); + AcceptSocket = new Socket(IPAddress.Any.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + AcceptSocket.Bind(new IPEndPoint(IPAddress.Any, 0)); + AcceptSocket.Listen(50); + Reply[0] = 5; //Version 5 + Reply[1] = 0; //Everything is ok :) + Reply[2] = 0; //Reserved + Reply[3] = 1; //We're going to send a IPv4 address + Reply[4] = LocalIP[0];// (byte)(Math.Floor((double)(LocalIP % 256))); //IP Address/1 + Reply[5] = LocalIP[1];//(byte)(Math.Floor((double)(LocalIP % 65536) / 256)); //IP Address/2 + Reply[6] = LocalIP[2];//(byte)(Math.Floor((double)(LocalIP % 16777216) / 65536)); //IP Address/3 + Reply[7] = LocalIP[3];//(byte)(Math.Floor((double)(LocalIP / 16777216))); //IP Address/4 + Reply[8] = (byte)(Math.Floor((double)((IPEndPoint)AcceptSocket.LocalEndPoint).Port / 256)); //Port/1 + Reply[9] = (byte)(((IPEndPoint)AcceptSocket.LocalEndPoint).Port % 256); //Port/2 + Connection.BeginSend(Reply, 0, Reply.Length, SocketFlags.None, new AsyncCallback(this.OnStartAccept), Connection); + break; + case 3: //ASSOCIATE + //ASSOCIATE is not implemented (yet?) + Dispose(7); + break; + default: + Dispose(7); + break; + } + } catch { + Dispose(1); + } + } + ///Called when we're successfully connected to the remote host. + ///The result of the asynchronous operation. + private void OnConnected(IAsyncResult ar) { + try { + RemoteConnection.EndConnect(ar); + Dispose(0); + } catch { + Dispose(1); + } + } + ///Called when there's an incoming connection in the AcceptSocket queue. + ///The result of the asynchronous operation. + protected override void OnAccept(IAsyncResult ar) { + try { + RemoteConnection = AcceptSocket.EndAccept(ar); + AcceptSocket.Close(); + AcceptSocket = null; + Dispose(0); + } catch { + Dispose(1); + } + } + ///Sends a reply to the client connection and disposes it afterwards. + ///A byte that contains the reply code to send to the client. + protected override void Dispose(byte Value) { + byte [] ToSend; + try { + ToSend = new byte[]{5, Value, 0, 1, + ((IPEndPoint)RemoteConnection.LocalEndPoint).Address.GetAddressBytes()[0], + ((IPEndPoint)RemoteConnection.LocalEndPoint).Address.GetAddressBytes()[1], + ((IPEndPoint)RemoteConnection.LocalEndPoint).Address.GetAddressBytes()[2], + ((IPEndPoint)RemoteConnection.LocalEndPoint).Address.GetAddressBytes()[3], + (byte)(Math.Floor((double)((IPEndPoint)RemoteConnection.LocalEndPoint).Port / 256)), + (byte)(((IPEndPoint)RemoteConnection.LocalEndPoint).Port % 256)}; + } catch { + ToSend = new byte[] {5, 1, 0, 1, 0, 0, 0, 0, 0, 0}; + } + try { + Connection.BeginSend(ToSend, 0, ToSend.Length, SocketFlags.None, (AsyncCallback)(ToSend[1] == 0 ? new AsyncCallback(this.OnDisposeGood) : new AsyncCallback(this.OnDisposeBad)), Connection); + } catch { + Dispose(false); + } + } + ///Gets or sets the the AuthBase object to use when trying to authenticate the SOCKS client. + ///The AuthBase object to use when trying to authenticate the SOCKS client. + ///The specified value is null. + private AuthBase AuthMethod { + get { + return m_AuthMethod; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_AuthMethod = value; + } + } + ///Gets or sets the AuthenticationList object to use when trying to authenticate the SOCKS client. + ///The AuthenticationList object to use when trying to authenticate the SOCKS client. + private AuthenticationList AuthList { + get { + return m_AuthList; + } + set { + m_AuthList = value; + } + } + // private variables + /// Holds the value of the AuthList property. + private AuthenticationList m_AuthList; + /// Holds the value of the AuthMethod property. + private AuthBase m_AuthMethod; +} + +} diff --git a/ProxyServer/SocksClient.cs b/ProxyServer/SocksClient.cs new file mode 100644 index 0000000..96c2a04 --- /dev/null +++ b/ProxyServer/SocksClient.cs @@ -0,0 +1,154 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; +using Org.Mentalis.Proxy; +using Org.Mentalis.Proxy.Socks.Authentication; + +namespace Org.Mentalis.Proxy.Socks { + +///Relays data between a remote host and a local client, using the SOCKS protocols. +///This class implements the SOCKS4, SOCKS4a and SOCKS5 protocols. +///If the MustAuthenticate property is set, only SOCKS5 connections are allowed and the AuthList parameter of the constructor should not be null. +public sealed class SocksClient : Client { + ///Initializes a new instance of the SocksClient class. + ///The Socket connection between this proxy server and the local client. + ///The method to be called when this SocksClient object disconnects from the local client and the remote server. + ///The list with valid username/password combinations. + ///If the AuthList is non-null, every client has to authenticate before he can use this proxy server to relay data. If it is null, the clients don't have to authenticate. + public SocksClient(Socket ClientSocket, DestroyDelegate Destroyer, AuthenticationList AuthList) : base(ClientSocket, Destroyer) { + this.AuthList = AuthList; + } + ///Gets or sets the SOCKS handler to be used when communicating with the client. + ///The SocksHandler to be used when communicating with the client. + internal SocksHandler Handler { + get { + return m_Handler; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_Handler = value; + } + } + ///Gets or sets the SOCKS handler to be used when communicating with the client. + ///The SocksHandler to be used when communicating with the client. + public bool MustAuthenticate { + get { + return m_MustAuthenticate; + } + set { + m_MustAuthenticate = value; + } + } + ///Starts communication with the client. + public override void StartHandshake() { + try { + ClientSocket.BeginReceive(Buffer, 0, 1, SocketFlags.None, new AsyncCallback(this.OnStartSocksProtocol), ClientSocket); + } catch { + Dispose(); + } + } + ///Called when we have received some data from the client. + ///The result of the asynchronous operation. + private void OnStartSocksProtocol(IAsyncResult ar) { + int Ret; + try { + Ret = ClientSocket.EndReceive(ar); + if (Ret <= 0) { + Dispose(); + return; + } + if (Buffer[0] == 4) { //SOCKS4 Protocol + if (MustAuthenticate) { + Dispose(); + return; + } else { + Handler = new Socks4Handler(ClientSocket, new NegotiationCompleteDelegate(this.OnEndSocksProtocol)); + } + } else if(Buffer[0] == 5) { //SOCKS5 Protocol + if (MustAuthenticate && AuthList == null) { + Dispose(); + return; + } + Handler = new Socks5Handler(ClientSocket, new NegotiationCompleteDelegate(this.OnEndSocksProtocol), AuthList); + } else { + Dispose(); + return; + } + Handler.StartNegotiating(); + } catch { + Dispose(); + } + } + ///Called when the SOCKS protocol has ended. We can no start relaying data, if the SOCKS authentication was successful. + ///Specifies whether the SOCKS negotiation was successful or not. + ///The connection with the remote server. + private void OnEndSocksProtocol(bool Success, Socket Remote) { + DestinationSocket = Remote; + if (Success) + StartRelay(); + else + Dispose(); + } + ///Gets or sets the AuthenticationList to use when a computer tries to authenticate on the proxy server. + ///An instance of the AuthenticationList class that contains all the valid username/password combinations. + private AuthenticationList AuthList { + get { + return m_AuthList; + } + set { + m_AuthList = value; + } + } + ///Returns text information about this SocksClient object. + ///A string representing this SocksClient object. + public override string ToString() { + try { + if (Handler != null) + return Handler.Username + " (" + ((IPEndPoint)ClientSocket.LocalEndPoint).Address.ToString() +") connected to " + DestinationSocket.RemoteEndPoint.ToString(); + else + return "SOCKS connection from " + ((IPEndPoint)ClientSocket.LocalEndPoint).Address.ToString(); + } catch { + return "Incoming SOCKS connection"; + } + } + // private variables + /// Holds the value of the AuthList property. + private AuthenticationList m_AuthList; + /// Holds the value of the MustAuthenticate property. + private bool m_MustAuthenticate = false; + /// Holds the value of the Handler property. + private SocksHandler m_Handler; +} + +} diff --git a/ProxyServer/SocksHandler.cs b/ProxyServer/SocksHandler.cs new file mode 100644 index 0000000..841a9a6 --- /dev/null +++ b/ProxyServer/SocksHandler.cs @@ -0,0 +1,241 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; +using Org.Mentalis.Proxy; + +namespace Org.Mentalis.Proxy.Socks { + +///Defines the signature of the method that's called when the SOCKS negotiation is complete. +///Indicates whether the negotiation was successful or not. +///The connection with the remote server. +internal delegate void NegotiationCompleteDelegate(bool Success, Socket Remote); + +///Implements a specific version of the SOCKS protocol. +internal abstract class SocksHandler { + ///Initializes a new instance of the SocksHandler class. + ///The connection with the client. + ///The method to call when the SOCKS negotiation is complete. + ///Callback is null. + public SocksHandler(Socket ClientConnection, NegotiationCompleteDelegate Callback) { + if (Callback == null) + throw new ArgumentNullException(); + Connection = ClientConnection; + Signaler = Callback; + } + ///Gets or sets the username of the SOCKS user. + ///A String representing the username of the logged on user. + ///The specified value is null. + internal string Username { + get { + return m_Username; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_Username = value; + } + } + ///Gets or sets the connection with the client. + ///A Socket representing the connection between the proxy server and the SOCKS client. + ///The specified value is null. + protected Socket Connection { + get { + return m_Connection; + } + set { + if (value == null) + throw new ArgumentNullException(); + m_Connection = value; + } + } + ///Gets a buffer that can be used when receiving bytes from the client. + ///A byte array that can be used when receiving bytes from the client. + protected byte[] Buffer { + get { + return m_Buffer; + } + } + ///Gets or sets a byte array that can be used to store received bytes from the client. + ///A byte array that can be used to store bytes from the client. + protected byte[] Bytes { + get { + return m_Bytes; + } + set { + m_Bytes = value; + } + } + ///Gets or sets the connection with the remote host. + ///A Socket representing the connection between the proxy server and the remote host. + ///The specified value is null. + protected Socket RemoteConnection { + get { + return m_RemoteConnection; + } + set { + m_RemoteConnection = value; + try { + m_RemoteConnection.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, 1); + } catch {} + } + } + ///Gets or sets the socket that is used to accept incoming connections. + ///A Socket that is used to accept incoming connections. + protected Socket AcceptSocket { + get { + return m_AcceptSocket; + } + set { + m_AcceptSocket = value; + } + } + ///Gets or sets the IP address of the requested remote server. + ///An IPAddress object specifying the address of the requested remote server. + protected IPAddress RemoteBindIP { + get { + return m_RemoteBindIP; + } + set { + m_RemoteBindIP = value; + } + } + ///Closes the listening socket if present, and signals the parent object that SOCKS negotiation is complete. + ///Indicates whether the SOCKS negotiation was successful or not. + protected void Dispose(bool Success) { + if (AcceptSocket != null) + AcceptSocket.Close(); + Signaler(Success, RemoteConnection); + } + ///Starts accepting bytes from the client. + public void StartNegotiating() { + try { + Connection.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceiveBytes), Connection); + } catch { + Dispose(false); + } + } + ///Called when we receive some bytes from the client. + ///The result of the asynchronous operation. + protected void OnReceiveBytes(IAsyncResult ar) { + try { + int Ret = Connection.EndReceive(ar); + if (Ret <= 0) + Dispose(false); + AddBytes(Buffer, Ret); + if (IsValidRequest(Bytes)) + ProcessRequest(Bytes); + else + Connection.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceiveBytes), Connection); + } catch { + Dispose(false); + } + } + ///Called when an OK reply has been sent to the client. + ///The result of the asynchronous operation. + protected void OnDisposeGood(IAsyncResult ar) { + try { + if (Connection.EndSend(ar) > 0) { + Dispose(true); + return; + } + } catch {} + Dispose(false); + } + ///Called when a negative reply has been sent to the client. + ///The result of the asynchronous operation. + protected void OnDisposeBad(IAsyncResult ar) { + try { + Connection.EndSend(ar); + } catch {} + Dispose(false); + } + ///Adds some bytes to a byte aray. + ///The new bytes to add. + ///The number of bytes to add. + protected void AddBytes(byte [] NewBytes, int Cnt) { + if (Cnt <= 0 || NewBytes == null || Cnt > NewBytes.Length) + return; + if (Bytes == null) { + Bytes = new byte[Cnt]; + } else { + byte [] tmp = Bytes; + Bytes = new byte[Bytes.Length + Cnt]; + Array.Copy(tmp, 0, Bytes, 0, tmp.Length); + } + Array.Copy(NewBytes, 0, Bytes, Bytes.Length - Cnt, Cnt); + } + ///Called when the AcceptSocket should start accepting incoming connections. + ///The result of the asynchronous operation. + protected void OnStartAccept(IAsyncResult ar) { + try { + if (Connection.EndSend(ar) <= 0) + Dispose(false); + else + AcceptSocket.BeginAccept(new AsyncCallback(this.OnAccept), AcceptSocket); + } catch { + Dispose(false); + } + } + ///Called when there's an incoming connection in the AcceptSocket queue. + ///The result of the asynchronous operation. + protected abstract void OnAccept(IAsyncResult ar); + ///Sends a reply to the client connection and disposes it afterwards. + ///A byte that contains the reply code to send to the client. + protected abstract void Dispose(byte Value); + ///Checks whether a specific request is a valid SOCKS request or not. + ///The request array to check. + ///True is the specified request is valid, false otherwise + protected abstract bool IsValidRequest(byte [] Request); + ///Processes a SOCKS request from a client. + ///The request to process. + protected abstract void ProcessRequest(byte [] Request); + // private variables + /// Holds the value of the Username property. + private string m_Username; + /// Holds the value of the Buffer property. + private byte [] m_Buffer = new byte[1024]; + /// Holds the value of the Bytes property. + private byte [] m_Bytes; + /// Holds the value of the RemoteConnection property. + private Socket m_RemoteConnection; + /// Holds the value of the Connection property. + private Socket m_Connection; + /// Holds the value of the AcceptSocket property. + private Socket m_AcceptSocket; + /// Holds the value of the RemoteBindIP property. + private IPAddress m_RemoteBindIP; + /// Holds the address of the method to call when the SOCKS negotiation is complete. + private NegotiationCompleteDelegate Signaler; +} + +} diff --git a/ProxyServer/SocksListener.cs b/ProxyServer/SocksListener.cs new file mode 100644 index 0000000..a31a361 --- /dev/null +++ b/ProxyServer/SocksListener.cs @@ -0,0 +1,114 @@ +/* + Copyright 2002, The KPD-Team + All rights reserved. + http://www.mentalis.org/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Neither the name of the KPD-Team, nor the names of its contributors + may be used to endorse or promote products derived from this + software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +using System; +using System.Net; +using System.Net.Sockets; +using Org.Mentalis.Proxy; +using Org.Mentalis.Proxy.Socks.Authentication; + +namespace Org.Mentalis.Proxy.Socks { + +///Listens on a specific port on the proxy server for incoming SOCKS4 and SOCKS5 requests. +///This class also implements the SOCKS4a protocol. +public sealed class SocksListener : Listener { + ///Initializes a new instance of the SocksListener class. + ///The port to listen on. + ///The SocksListener will listen on all available network cards and it will not use an AuthenticationList. + public SocksListener(int Port) : this(IPAddress.Any, Port, null) {} + ///Initializes a new instance of the SocksListener class. + ///The port to listen on. + ///The address to listen on. You can specify IPAddress.Any to listen on all installed network cards. + ///For the security of your server, try to avoid to listen on every network card (IPAddress.Any). Listening on a local IP address is usually sufficient and much more secure. + ///The SocksListener object will not use an AuthenticationList. + public SocksListener(IPAddress Address, int Port) : this(Address, Port, null) {} + ///Initializes a new instance of the SocksListener class. + ///The port to listen on. + ///The list of valid login/password combinations. If you do not need password authentication, set this parameter to null. + ///The SocksListener will listen on all available network cards. + public SocksListener(int Port, AuthenticationList AuthList) : this(IPAddress.Any, Port, AuthList) {} + ///Initializes a new instance of the SocksListener class. + ///The port to listen on. + ///The address to listen on. You can specify IPAddress.Any to listen on all installed network cards. + ///The list of valid login/password combinations. If you do not need password authentication, set this parameter to null. + ///For the security of your server, try to avoid to listen on every network card (IPAddress.Any). Listening on a local IP address is usually sufficient and much more secure. + public SocksListener(IPAddress Address, int Port, AuthenticationList AuthList) : base(Port, Address) { + this.AuthList = AuthList; + } + ///Called when there's an incoming client connection waiting to be accepted. + ///The result of the asynchronous operation. + public override void OnAccept(IAsyncResult ar) { + try { + Socket NewSocket = ListenSocket.EndAccept(ar); + if (NewSocket != null) { + SocksClient NewClient = new SocksClient(NewSocket, new DestroyDelegate(this.RemoveClient), AuthList); + AddClient(NewClient); + NewClient.StartHandshake(); + } + } catch {} + try { + //Restart Listening + ListenSocket.BeginAccept(new AsyncCallback(this.OnAccept), ListenSocket); + } catch { + Dispose(); + } + } + ///Gets or sets the AuthenticationList to be used when a SOCKS5 client connects. + ///An AuthenticationList that is to be used when a SOCKS5 client connects. + ///This value can be null. + private AuthenticationList AuthList { + get { + return m_AuthList; + } + set { + m_AuthList = value; + } + } + ///Returns a string representation of this object. + ///A string with information about this object. + public override string ToString() { + return "SOCKS service on " + Address.ToString() + ":" + Port.ToString(); + } + ///Returns a string that holds all the construction information for this object. + ///A string that holds all the construction information for this object. + public override string ConstructString { + get { + if (AuthList == null) + return "host:" + Address.ToString() + ";int:" + Port.ToString()+ ";null"; + else + return "host:" + Address.ToString() + ";int:" + Port.ToString()+ ";authlist"; + } + } + // private variables + /// Holds the value of the AuthList property. + private AuthenticationList m_AuthList; +} + +} diff --git a/WebServiceDefAndSchemas/MSNABSharingService/msnab_datatypes.xsd b/WebServiceDefAndSchemas/MSNABSharingService/msnab_datatypes.xsd new file mode 100644 index 0000000..d664b02 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNABSharingService/msnab_datatypes.xsd @@ -0,0 +1,926 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A space (ASCII #32) separated list of properties that + have changed as part of an update request. The property + names don't always match the name of the associated + element. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Indicates whether the contact has a Windows Live + Space or not. + + + + + + + + + + + + + Seen is YYYY/MM/DD format. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A space (ASCII #32) separated list of properties that + have changed as part of an update request. The property + names don't always match the name of the associated + element. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNABSharingService/msnab_servicetypes.xsd b/WebServiceDefAndSchemas/MSNABSharingService/msnab_servicetypes.xsd new file mode 100644 index 0000000..4e149f3 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNABSharingService/msnab_servicetypes.xsd @@ -0,0 +1,600 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNABSharingService/msnab_sharingservice.wsdl b/WebServiceDefAndSchemas/MSNABSharingService/msnab_sharingservice.wsdl new file mode 100644 index 0000000..126f0b5 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNABSharingService/msnab_sharingservice.wsdl @@ -0,0 +1,607 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNOIMStoreService/oim_servicetypes.xsd b/WebServiceDefAndSchemas/MSNOIMStoreService/oim_servicetypes.xsd new file mode 100644 index 0000000..3d6da61 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNOIMStoreService/oim_servicetypes.xsd @@ -0,0 +1,60 @@ + + + + + + + + + + This field must be encoded according to RFC 2047. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNOIMStoreService/oim_ws.wsdl b/WebServiceDefAndSchemas/MSNOIMStoreService/oim_ws.wsdl new file mode 100644 index 0000000..caea686 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNOIMStoreService/oim_ws.wsdl @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNOIMStoreService/utility.xsd b/WebServiceDefAndSchemas/MSNOIMStoreService/utility.xsd new file mode 100644 index 0000000..69f1261 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNOIMStoreService/utility.xsd @@ -0,0 +1,203 @@ + + + + + + +This type defines the fault code value for Timestamp message expiration. + + + + + + + + + +This type defines the fault code values for context-related faults. + + + + + + + + + + + + + +This global attribute supports annotating arbitrary elements with an ID. + + + + + + +This global attribute is used on extensions to distinguish mandatory vs. optional extensions. + + + + + + +Convenience attribute group used to simplify this schema. + + + + + + + + +This type is for elements whose [children] is a psuedo-dateTime and can have arbitrary attributes. + + + + + + + +This attribute indicates the actual schema type of the element [children]. +If the ValueType attribute is present, conforming processors must process the string value of [children] as if it were affiliated with the type indicated by this attribute. +If the ValueType attribute is absent, the implied value of this attribute is xsd:dateTime. + + + + + + + + + + +This type extends AnnotatedDateTime to add a Delay attribute. + + + + + + + +This attribute indicates the number of milliseconds that this actor processed this message. + + + + + + +This attribute indicates the intermediary that processed this message. + + + + + + + + + +This type is for elements whose [children] is an anyURI and can have arbitrary attributes. + + + + + + + + + + + +This complex type ties together the timestamp related elements into a composite type. + + + + + + + + + + + + + + + +This element allows Timestamps to be applied anywhere element wildcards are present, +including as a SOAP header. + + + + + + +This element allows an expiration time to be applied anywhere element wildcards are present. + + + + + + +This element allows a creation time to be applied anywhere element wildcards are present. + + + + + + +This element allows the ReceviedType to be applied anywhere element wildcards are present, including a Timestamp header. + + + + + + + +This type is the generic base type for context headers. + + + + + + + + + + + +This element allows Contexts to be applied anywhere element wildcards are present, +including as a SOAP header. + + + + + + + + + + + + + + + +This complex type defines a lightweight type for transmitting ports. + + + + + + + + + + + +This element allows port references to be applied anywhere element wildcards are present. + + + + diff --git a/WebServiceDefAndSchemas/MSNOIMStoreService/wsrm.xsd b/WebServiceDefAndSchemas/MSNOIMStoreService/wsrm.xsd new file mode 100644 index 0000000..6b66d96 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNOIMStoreService/wsrm.xsd @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNRSIService/rsi_datatypes.xsd b/WebServiceDefAndSchemas/MSNRSIService/rsi_datatypes.xsd new file mode 100644 index 0000000..cff35a3 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNRSIService/rsi_datatypes.xsd @@ -0,0 +1,67 @@ + + + + + + + + 11 + + + + + 6 + + + + + The time the message was received. + + + + + Read set. + + + + + The size of the message. + + + + + The passport name of the sender. + + + + + The unique ID for this message. Seems to be a GUID. + + + + + Hotmail folder GUID. 000009 or .!!OIM + + + + + RFC 2047-encoded friendly name of the sender. + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNRSIService/rsi_faulttypes.xsd b/WebServiceDefAndSchemas/MSNRSIService/rsi_faulttypes.xsd new file mode 100644 index 0000000..1be76c3 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNRSIService/rsi_faulttypes.xsd @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNRSIService/rsi_servicetypes.xsd b/WebServiceDefAndSchemas/MSNRSIService/rsi_servicetypes.xsd new file mode 100644 index 0000000..7d74d33 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNRSIService/rsi_servicetypes.xsd @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNRSIService/rsi_ws.wsdl b/WebServiceDefAndSchemas/MSNRSIService/rsi_ws.wsdl new file mode 100644 index 0000000..b4fe0a7 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNRSIService/rsi_ws.wsdl @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/WS-Trust.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/WS-Trust.xsd new file mode 100644 index 0000000..634a727 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/WS-Trust.xsd @@ -0,0 +1,386 @@ + + + + + + + + + + + + + + Actual content model is non-deterministic, hence wildcard. The following shows intended content model: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Actual content model is non-deterministic, hence wildcard. The following shows intended content model: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/addressing-04-08.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/addressing-04-08.xsd new file mode 100644 index 0000000..996e1bd --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/addressing-04-08.xsd @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + If "Policy" elements from namespace "http://schemas.xmlsoap.org/ws/2002/12/policy#policy" are used, they must appear first (before any extensibility elements). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/addressing.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/addressing.xsd new file mode 100644 index 0000000..996e1bd --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/addressing.xsd @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + If "Policy" elements from namespace "http://schemas.xmlsoap.org/ws/2002/12/policy#policy" are used, they must appear first (before any extensibility elements). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/oasis-200401-wss-wssecurity-secext-1.0.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/oasis-200401-wss-wssecurity-secext-1.0.xsd new file mode 100644 index 0000000..7a3cb49 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/oasis-200401-wss-wssecurity-secext-1.0.xsd @@ -0,0 +1,196 @@ + + + + + + + + + + This type represents an element with arbitrary attributes. + + + + + + + + + + + This type is used for password elements per Section 4.1. + + + + + + + + + + This type is used for elements containing stringified binary data. + + + + + + + + + + This type represents a username token per Section 4.1 + + + + + + + + + + + A security token that is encoded in binary + + + + + + + + + + A security token key identifier + + + + + + + + + + Typedef to allow a list of usages (as URIs). + + + + + + This global attribute is used to indicate the usage of a referenced or indicated token within the containing context + + + + + This type represents a reference to an external security token. + + + + + + + + This type represents a reference to an embedded security token. + + + + + + + + + + This type is used reference a security token. + + + + + + + + + + + This complexType defines header block to use for security-relevant data directed at a specific SOAP actor. + + + + + The use of "any" is to allow extensibility and different forms of security data. + + + + + + + + This complexType defines a container for elements to be specified from any namespace as properties/parameters of a DSIG transformation. + + + + + The use of "any" is to allow extensibility from any namespace. + + + + + + + + This element defines the wsse:UsernameToken element per Section 4.1. + + + + + This element defines the wsse:BinarySecurityToken element per Section 4.2. + + + + + This element defines a security token reference + + + + + This element defines a security token embedded reference + + + + + This element defines a key identifier reference + + + + + This element defines the wsse:SecurityTokenReference per Section 4.3. + + + + + This element defines the wsse:Security SOAP header element per Section 4. + + + + + This element contains properties for transformations from any namespace, including DSIG. + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/oasis-200401-wss-wssecurity-utility-1.0.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/oasis-200401-wss-wssecurity-utility-1.0.xsd new file mode 100644 index 0000000..f8d74e9 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/oasis-200401-wss-wssecurity-utility-1.0.xsd @@ -0,0 +1,108 @@ + + + + + + + +This type defines the fault code value for Timestamp message expiration. + + + + + + + + + + +This global attribute supports annotating arbitrary elements with an ID. + + + + + + +Convenience attribute group used to simplify this schema. + + + + + + + + + +This type is for elements whose [children] is a psuedo-dateTime and can have arbitrary attributes. + + + + + + + + + + + +This type is for elements whose [children] is an anyURI and can have arbitrary attributes. + + + + + + + + + + + + +This complex type ties together the timestamp related elements into a composite type. + + + + + + + + + + + + + + +This element allows Timestamps to be applied anywhere element wildcards are present, +including as a SOAP header. + + + + + + + +This element allows an expiration time to be applied anywhere element wildcards are present. + + + + + + +This element allows a creation time to be applied anywhere element wildcards are present. + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/soap-env-03-05.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/soap-env-03-05.xsd new file mode 100644 index 0000000..85a6d8e --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/soap-env-03-05.xsd @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + Elements replacing the wildcard MUST be namespace qualified, but can be in the targetNamespace + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Fault reporting structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/ws-policy.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/ws-policy.xsd new file mode 100644 index 0000000..e2e04d9 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/ws-policy.xsd @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/ws-secureconversation.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/ws-secureconversation.xsd new file mode 100644 index 0000000..7ac25b0 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/ws-secureconversation.xsd @@ -0,0 +1,111 @@ + + + + + + + + + + + Actual content model is non-deterministic, hence wildcard. The following shows intended content model: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/xmldsig-core-schema.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/xmldsig-core-schema.xsd new file mode 100644 index 0000000..df126b3 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/Origin/xmldsig-core-schema.xsd @@ -0,0 +1,318 @@ + + + + + + ]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/addressing-04-08.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/addressing-04-08.xsd new file mode 100644 index 0000000..996e1bd --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/addressing-04-08.xsd @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + If "Policy" elements from namespace "http://schemas.xmlsoap.org/ws/2002/12/policy#policy" are used, they must appear first (before any extensibility elements). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/addressing.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/addressing.xsd new file mode 100644 index 0000000..c3f0d24 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/addressing.xsd @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/ps-fault.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/ps-fault.xsd new file mode 100644 index 0000000..5d754d8 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/ps-fault.xsd @@ -0,0 +1,120 @@ + + + + + + Comment describing your root element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/ps.wsdl b/WebServiceDefAndSchemas/MSNSecurityTokenService/ps.wsdl new file mode 100644 index 0000000..9de38a2 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/ps.wsdl @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/ps.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/ps.xsd new file mode 100644 index 0000000..a9c0643 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/ps.xsd @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/soap-env-03-05.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/soap-env-03-05.xsd new file mode 100644 index 0000000..18d415a --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/soap-env-03-05.xsd @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Elements replacing the wildcard MUST be namespace qualified, but can be in the targetNamespace + + + + + + + + + + + + + + + + + + + + + + + + + Fault reporting structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/soap-env.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/soap-env.xsd new file mode 100644 index 0000000..83c67dc --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/soap-env.xsd @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Prose in the spec does not specify that attributes are allowed on the Body element + + + + + + + + + + + + + + + + 'encodingStyle' indicates any canonicalization conventions followed in the contents of the containing element. For example, the value 'http://schemas.xmlsoap.org/soap/encoding/' indicates the pattern described in SOAP specification + + + + + + + + + + + + + Fault reporting structure + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/sstc-saml-schema-assertion-1.1-cs.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/sstc-saml-schema-assertion-1.1-cs.xsd new file mode 100644 index 0000000..79cfbbc --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/sstc-saml-schema-assertion-1.1-cs.xsd @@ -0,0 +1,201 @@ + + + + + + + Document identifier: sstc-saml-schema-assertion-1.1-cs + Location: http://www.oasis-open.org/committees/documents.php?wg_abbrev=security + Revision history: + V1.0 (November, 2002): + Initial standard schema. + V1.1 (May, 2003): + * Note that V1.1 of this schema has the same XML namespace as V1.0. + Rebased ID content directly on XML Schema types + Added DoNotCacheCondition element and DoNotCacheConditionType + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/sstc-saml-schema-protocol-1.1-cs.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/sstc-saml-schema-protocol-1.1-cs.xsd new file mode 100644 index 0000000..b2982c9 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/sstc-saml-schema-protocol-1.1-cs.xsd @@ -0,0 +1,133 @@ + + + + + + + + Document identifier: sstc-saml-schema-protocol-1.1-cs + Location: http://www.oasis-open.org/committees/documents.php?wg_abbrev=security + Revision history: + V1.0 (November, 2002): + Initial standard schema. + V1.1 (May, 2003): + * Note that V1.1 of this schema has the same XML namespace as V1.0. + Rebased ID content directly on XML Schema types + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/ws-policy.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/ws-policy.xsd new file mode 100644 index 0000000..5a09353 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/ws-policy.xsd @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/ws-secext.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/ws-secext.xsd new file mode 100644 index 0000000..e6e4685 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/ws-secext.xsd @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This element defines a security token reference + + + + + This type represents a reference to an external security token. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/ws-secureconversation.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/ws-secureconversation.xsd new file mode 100644 index 0000000..c65aa7a --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/ws-secureconversation.xsd @@ -0,0 +1,111 @@ + + + + + + + + + + + Actual content model is non-deterministic, hence wildcard. The following shows intended content model: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/ws-trust.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/ws-trust.xsd new file mode 100644 index 0000000..9f613a3 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/ws-trust.xsd @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/wss-utility.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/wss-utility.xsd new file mode 100644 index 0000000..3c0d8f0 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/wss-utility.xsd @@ -0,0 +1,104 @@ + + + + + + + + +This type defines the fault code value for Timestamp message expiration. + + + + + + + + + + +This global attribute supports annotating arbitrary elements with an ID. + + + + + + +Convenience attribute group used to simplify this schema. + + + + + + + + + +This type is for elements whose [children] is a psuedo-dateTime and can have arbitrary attributes. + + + + + + + + + + + +This type is for elements whose [children] is an anyURI and can have arbitrary attributes. + + + + + + + + + + + + +This complex type ties together the timestamp related elements into a composite type. + + + + + + + + + + + + + + +This element allows Timestamps to be applied anywhere element wildcards are present, +including as a SOAP header. + + + + + + + +This element allows an expiration time to be applied anywhere element wildcards are present. + + + + + + +This element allows a creation time to be applied anywhere element wildcards are present. + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/xenc-schema.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/xenc-schema.xsd new file mode 100644 index 0000000..0c85bf2 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/xenc-schema.xsd @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/xml.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/xml.xsd new file mode 100644 index 0000000..aea7d0d --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/xml.xsd @@ -0,0 +1,287 @@ + + + + + + +
+

About the XML namespace

+ +
+

+ This schema document describes the XML namespace, in a form + suitable for import by other schema documents. +

+

+ See + http://www.w3.org/XML/1998/namespace.html and + + http://www.w3.org/TR/REC-xml for information + about this namespace. +

+

+ Note that local names in this namespace are intended to be + defined only by the World Wide Web Consortium or its subgroups. + The names currently defined in this namespace are listed below. + They should not be used with conflicting semantics by any Working + Group, specification, or document instance. +

+

+ See further below in this document for more information about how to refer to this schema document from your own + XSD schema documents and about the + namespace-versioning policy governing this schema document. +

+
+
+
+
+ + + + +
+ +

lang (as an attribute name)

+

+ denotes an attribute whose value + is a language code for the natural language of the content of + any element; its value is inherited. This name is reserved + by virtue of its definition in the XML specification.

+ +
+
+

Notes

+

+ Attempting to install the relevant ISO 2- and 3-letter + codes as the enumerated possible values is probably never + going to be a realistic possibility. +

+

+ See BCP 47 at + http://www.rfc-editor.org/rfc/bcp/bcp47.txt + and the IANA language subtag registry at + + http://www.iana.org/assignments/language-subtag-registry + for further information. +

+

+ The union allows for the 'un-declaration' of xml:lang with + the empty string. +

+
+
+
+ + + + + + + + + +
+ + + + +
+ +

space (as an attribute name)

+

+ denotes an attribute whose + value is a keyword indicating what whitespace processing + discipline is intended for the content of the element; its + value is inherited. This name is reserved by virtue of its + definition in the XML specification.

+ +
+
+
+ + + + + + +
+ + + +
+ +

base (as an attribute name)

+

+ denotes an attribute whose value + provides a URI to be used as the base for interpreting any + relative URIs in the scope of the element on which it + appears; its value is inherited. This name is reserved + by virtue of its definition in the XML Base specification.

+ +

+ See http://www.w3.org/TR/xmlbase/ + for information about this attribute. +

+
+
+
+
+ + + + +
+ +

id (as an attribute name)

+

+ denotes an attribute whose value + should be interpreted as if declared to be of type ID. + This name is reserved by virtue of its definition in the + xml:id specification.

+ +

+ See http://www.w3.org/TR/xml-id/ + for information about this attribute. +

+
+
+
+
+ + + + + + + + + + +
+ +

Father (in any context at all)

+ +
+

+ denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and + XML Coordination groups: +

+
+

+ In appreciation for his vision, leadership and + dedication the W3C XML Plenary on this 10th day of + February, 2000, reserves for Jon Bosak in perpetuity + the XML name "xml:Father". +

+
+
+
+
+
+ + + +
+

About this schema document

+ +
+

+ This schema defines attributes and an attribute group suitable + for use by schemas wishing to allow xml:base, + xml:lang, xml:space or + xml:id attributes on elements they define. +

+

+ To enable this, such a schema must import this schema for + the XML namespace, e.g. as follows: +

+
+          <schema . . .>
+           . . .
+           <import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+     
+

+ or +

+
+           <import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
+     
+

+ Subsequently, qualified reference to any of the attributes or the + group defined below will have the desired effect, e.g. +

+
+          <type . . .>
+           . . .
+           <attributeGroup ref="xml:specialAttrs"/>
+     
+

+ will define a type which will schema-validate an instance element + with any of those attributes. +

+
+
+
+
+ + + +
+

Versioning policy for this schema document

+
+

+ In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + + http://www.w3.org/2009/01/xml.xsd. +

+

+ At the date of issue it can also be found at + + http://www.w3.org/2001/xml.xsd. +

+

+ The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML + Schema itself, or with the XML namespace itself. In other words, + if the XML Schema or XML namespaces change, the version of this + document at + http://www.w3.org/2001/xml.xsd + + will change accordingly; the version at + + http://www.w3.org/2009/01/xml.xsd + + will not change. +

+

+ Previous dated (and unchanging) versions of this schema + document are at: +

+ +
+
+
+
+ +
+ diff --git a/WebServiceDefAndSchemas/MSNSecurityTokenService/xmldsig-core-schema.xsd b/WebServiceDefAndSchemas/MSNSecurityTokenService/xmldsig-core-schema.xsd new file mode 100644 index 0000000..07779a4 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSecurityTokenService/xmldsig-core-schema.xsd @@ -0,0 +1,258 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSpaceService/space_ws.wsdl b/WebServiceDefAndSchemas/MSNSpaceService/space_ws.wsdl new file mode 100644 index 0000000..e6b3207 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSpaceService/space_ws.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSpaceService/space_ws_datatype.xsd b/WebServiceDefAndSchemas/MSNSpaceService/space_ws_datatype.xsd new file mode 100644 index 0000000..56191f0 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSpaceService/space_ws_datatype.xsd @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNSpaceService/space_ws_servicetype.xsd b/WebServiceDefAndSchemas/MSNSpaceService/space_ws_servicetype.xsd new file mode 100644 index 0000000..4596157 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNSpaceService/space_ws_servicetype.xsd @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNStorageService/msnstorage_datatypes.xsd b/WebServiceDefAndSchemas/MSNStorageService/msnstorage_datatypes.xsd new file mode 100644 index 0000000..e749d67 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNStorageService/msnstorage_datatypes.xsd @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNStorageService/msnstorage_servicetypes.xsd b/WebServiceDefAndSchemas/MSNStorageService/msnstorage_servicetypes.xsd new file mode 100644 index 0000000..64b1780 --- /dev/null +++ b/WebServiceDefAndSchemas/MSNStorageService/msnstorage_servicetypes.xsd @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WebServiceDefAndSchemas/MSNStorageService/msnstorage_ws.wsdl b/WebServiceDefAndSchemas/MSNStorageService/msnstorage_ws.wsdl new file mode 100644 index 0000000..34efb0a --- /dev/null +++ b/WebServiceDefAndSchemas/MSNStorageService/msnstorage_ws.wsdl @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +