PageRenderTime 2ms CodeModel.GetById 46ms app.highlight 14ms RepoModel.GetById 0ms app.codeStats 1ms

/Code/Channels/Exchange/ExchangeClientChannel.cs

https://github.com/csmaster2005/inbox2_desktop
C# | 415 lines | 302 code | 98 blank | 15 comment | 22 complexity | 478e57f9eff6e7b813a387b80d23c006 MD5 | raw file
  1using System;
  2using System.Collections.Generic;
  3using System.Linq;
  4using System.IO;
  5using System.Net;
  6using ExchangeServicesWsdlClient;
  7using Inbox2.Platform.Channels.Entities;
  8using Inbox2.Platform.Channels.Interfaces;
  9using Inbox2.Platform.Framework.Extensions;
 10using Inbox2.Platform.Logging;
 11using Logger = Inbox2.Platform.Logging.Logger;
 12
 13namespace Inbox2.Channels.Exchange
 14{
 15	public class ExchangeClientChannel : IClientInputChannel, IClientOutputChannel, IPagableChannel, IReadStateChannel, IClientContactsChannel, ILabelsChannel
 16    {
 17		private ChannelFolder folder;
 18		private List<ChannelFolder> folders;
 19
 20        #region Properties
 21
 22		public long StartIndex { get; set; }
 23
 24		public long EndIndex { get; set; }
 25
 26		public long PageSize { get; set; }
 27
 28		public ChannelProgressDelegate BytesRead { get; set; }
 29
 30		public ChannelProgressDelegate BytesWritten { get; set; }
 31  
 32        public string Hostname { get; set; }
 33
 34        public int Port { get; set; }
 35
 36        public bool IsSecured { get; set; }
 37
 38        public string Username
 39        {
 40            get { return CredentialsProvider.GetCredentials().Claim; }
 41        }
 42
 43        public string Password
 44        {
 45            get { return CredentialsProvider.GetCredentials().Evidence; }
 46        }
 47
 48        public bool IsEnabled { get; set; }
 49
 50        public int MaxConcurrentConnections { get; set; }
 51
 52        public IChannelCredentialsProvider CredentialsProvider { get; set; }
 53
 54        public string Protocol
 55        {
 56            get { return "ExchangeWS"; }
 57        }
 58
 59        public string SourceAdress
 60        {
 61            get
 62            {
 63                string username = CredentialsProvider.GetCredentials().Claim;
 64
 65                return username.Contains("@") ? username : String.Format("{0}@{1}", username, Hostname);
 66            }
 67        }
 68
 69		public LabelsSupport LabelsSupport
 70		{
 71			get { return LabelsSupport.Folders; }
 72		}
 73
 74		public string AuthMessage { get; private set; }
 75
 76        #endregion    	
 77
 78		public ConnectResult Connect()
 79        {
 80			var credentials = CredentialsProvider.GetCredentials();
 81			var binding = ChannelHelper.BuildChannel(Hostname, credentials.Claim, credentials.Evidence);
 82
 83			folders = new List<ChannelFolder>();
 84
 85			// Try connecting 
 86			HttpWebRequest request = (HttpWebRequest)WebRequest.Create(binding.Url);
 87			request.AllowAutoRedirect = false;
 88			request.Credentials = new NetworkCredential(credentials.Claim, credentials.Evidence);
 89
 90			try
 91			{
 92				HttpWebResponse response = (HttpWebResponse)request.GetResponse();
 93
 94				Logger.Debug("Server {0} returned status-code {1}", LogSource.Channel, binding.Url, response.StatusCode);
 95
 96				if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.Found)
 97					return ConnectResult.Success;
 98
 99				AuthMessage = String.Format("Statuscode {0}", response.StatusCode);
100
101				return ConnectResult.AuthFailure;
102			}
103			catch (Exception ex)
104			{
105				AuthMessage = ex.Message;
106
107				return ConnectResult.AuthFailure;
108			}
109        }
110
111        public IEnumerable<ChannelFolder> GetFolders()
112        {
113			var client = new ExchangeClient(Hostname, CredentialsProvider);
114
115			// inbox
116        	var inbox = client.GetFolder(DistinguishedFolderIdNameType.inbox);
117			folders.Add(new ChannelFolder(inbox.FolderId.Id, inbox.DisplayName, ChannelFolderType.Inbox));
118			folders.AddRange(GetChildFolders(client, inbox.FolderId.Id, ChannelFolderType.Label));
119
120			// sent items
121			var sent = client.GetFolder(DistinguishedFolderIdNameType.sentitems);
122        	folders.Add(new ChannelFolder(sent.FolderId.Id, sent.DisplayName, ChannelFolderType.SentItems));
123			folders.AddRange(GetChildFolders(client, sent.FolderId.Id, ChannelFolderType.SentItems));
124
125			// trash
126			var trash = client.GetFolder(DistinguishedFolderIdNameType.deleteditems);
127			folders.Add(new ChannelFolder(trash.FolderId.Id, trash.DisplayName, ChannelFolderType.Trash));
128
129			// spam
130			var spam = client.GetFolder(DistinguishedFolderIdNameType.junkemail);
131			folders.Add(new ChannelFolder(spam.FolderId.Id, spam.DisplayName, ChannelFolderType.Spam));
132
133        	return folders;
134        }
135
136		IEnumerable<ChannelFolder> GetChildFolders(ExchangeClient client, string folderId, ChannelFolderType folderType)
137		{
138			var childFolders = client.FindAllFolders(folderId);
139
140			return childFolders.Select(f => new ChannelFolder(f.FolderId.Id, f.DisplayName, folderType));
141		}
142
143		public void SelectFolder(ChannelFolder folder)
144        {
145        	this.folder = folder;
146        }
147
148        public IEnumerable<ChannelMessageHeader> GetHeaders()
149        {
150        	var client = new ExchangeClient(Hostname, CredentialsProvider);
151
152			foreach (MessageType inboxItem in client.GetHeaders(folder).Reverse().Skip((int)StartIndex).Take((int)PageSize))
153            {
154				var header = new ChannelMessageHeader
155	             	{	             		
156	             		MessageNumber = inboxItem.ItemId.Id,
157	             		MessageIdentifier = inboxItem.InternetMessageId,
158	             		Context = inboxItem.Subject,
159						// Not sending size because exchange changes can the size due
160						// to user actions usch as change priority.
161	             		//Size = inboxItem.Size,
162	             		DateReceived = inboxItem.DateTimeReceived,
163						IsRead = inboxItem.IsRead,
164						// Not processing IsStarred because somebody could send you an 
165						// email with importance: high and would end up getting starred;
166						// feature just asking for abuse :-)
167						//IsStarred = inboxItem.Importance == ImportanceChoicesType.High,
168	             	};
169
170            	yield return header;                                     
171            }            
172        }
173		
174        public IEnumerable<ChannelMessage> GetMessage(ChannelMessageHeader header)
175        {
176			var client = new ExchangeClient(Hostname, CredentialsProvider);
177
178			ChannelMessage message = new ChannelMessage();
179			MessageType inboxItem = client.GetMessage(header.MessageNumber);
180
181			// Now the message Body is there.
182			BodyType messageBody = inboxItem.Body;
183
184			message.Size = header.Size;
185			message.MessageNumber = header.MessageNumber;
186			message.MessageIdentifier = header.MessageIdentifier;
187			message.Context = header.Context;
188			message.From = new SourceAddress(inboxItem.From.Item.EmailAddress, inboxItem.From.Item.Name);
189			
190			if (inboxItem.ToRecipients != null)
191				foreach (var toRecipient in inboxItem.ToRecipients)
192					message.To.Add(new SourceAddress(toRecipient.EmailAddress, toRecipient.Name));
193
194			if (inboxItem.CcRecipients != null)
195				foreach (var ccRecipient in inboxItem.CcRecipients)
196					message.CC.Add(new SourceAddress(ccRecipient.EmailAddress, ccRecipient.Name));
197
198			if (inboxItem.BccRecipients != null)
199				foreach (var bccRecipient in inboxItem.BccRecipients)
200					message.BCC.Add(new SourceAddress(bccRecipient.EmailAddress, bccRecipient.Name));
201
202			message.InReplyTo = inboxItem.InReplyTo;
203			message.Metadata = header.Metadata;
204			message.IsRead = inboxItem.IsRead;
205			message.BodyHtml = messageBody.Value.ToStream();
206			message.DateReceived = header.DateReceived;
207
208			if (inboxItem.Attachments != null)
209			{
210				foreach (AttachmentType exchAttachment in inboxItem.Attachments)
211				{
212					var fileAttachment = client.GetAttachment(exchAttachment.AttachmentId.Id);
213
214					message.Attachments.Add(new ChannelAttachment
215	                 	{
216	                 		Filename = fileAttachment.Name,
217	                 		ContentType = ContentType.Attachment,
218	                 		ContentStream = new MemoryStream(fileAttachment.Content)
219	                 	});
220				}
221			}                    
222            
223            yield return message;
224        }
225
226		public void Send(ChannelMessage message)
227		{
228			var client = new ExchangeClient(Hostname, CredentialsProvider);
229
230			var messageId = client.SaveMessage(message);
231
232			// Upload attachments
233			if (message.Attachments.Count > 0)
234				client.SaveAttachments(messageId, message);
235
236			// Refresh and send message by message-id
237			client.SendMessage(client.GetMessageId(messageId.Id).ItemId);
238		}
239		
240        public bool Disconnect()
241        {
242            return true;
243        }
244
245        public IClientInputChannel Clone()
246        {
247            return new ExchangeClientChannel
248		    	{
249		    		Hostname = Hostname,
250		    		Port = Port,
251		    		IsSecured = IsSecured,
252		    		MaxConcurrentConnections = MaxConcurrentConnections,
253		    		CredentialsProvider = CredentialsProvider
254		    	};
255        }
256
257        public void Dispose()
258        {            
259        }
260
261		public long GetNumberOfItems()
262		{
263			var client = new ExchangeClient(Hostname, CredentialsProvider);
264
265			return client.GetNrItemsInFolder(folder);
266		}
267
268		public void MarkRead(ChannelMessageHeader message)
269		{
270			var client = new ExchangeClient(Hostname, CredentialsProvider);
271			var messageId = client.GetMessageId(message.MessageNumber).ItemId;
272
273			client.SetMessageReadState(messageId, true);
274		}
275
276		public void MarkUnread(ChannelMessageHeader message)
277		{
278			var client = new ExchangeClient(Hostname, CredentialsProvider);
279			var messageId = client.GetMessageId(message.MessageNumber).ItemId;
280
281			client.SetMessageReadState(messageId, false);
282		}
283
284		public void MarkDeleted(ChannelMessageHeader message)
285		{
286			var trash = GetFolders().First(f => f.FolderType == ChannelFolderType.Trash);
287
288			var client = new ExchangeClient(Hostname, CredentialsProvider);
289			var messageId = client.GetMessageId(message.MessageNumber).ItemId;
290
291			client.MoveMessageToFolder(messageId, trash.FolderId);	
292		}
293
294		public void SetStarred(ChannelMessageHeader message, bool starred)
295		{
296			var client = new ExchangeClient(Hostname, CredentialsProvider);
297			var messageId = client.GetMessageId(message.MessageNumber).ItemId;
298
299			client.SetMessageImportance(messageId, starred);
300		}
301
302		public void Purge(ChannelMessageHeader message)
303		{
304			var client = new ExchangeClient(Hostname, CredentialsProvider);
305			var messageId = client.GetMessageId(message.MessageNumber).ItemId;
306
307			client.DeleteMessage(messageId);
308		}
309
310		public ChannelFolder CreateFolder(string folderName)
311		{
312			var client = new ExchangeClient(Hostname, CredentialsProvider);
313			var folderId = client.CreateFolder(folderName, folders.First(f => f.FolderType == ChannelFolderType.Inbox).FolderId);
314
315			var newFolder = new ChannelFolder(folderId, folderName, ChannelFolderType.Label);
316
317			folders.Add(newFolder);
318
319			return newFolder;
320		}
321
322		public void MoveToFolder(ChannelMessageHeader message, ChannelFolder folder)
323		{
324			var client = new ExchangeClient(Hostname, CredentialsProvider);
325			var messageId = client.GetMessageId(message.MessageNumber).ItemId;
326
327			client.MoveMessageToFolder(messageId, folder.FolderId);
328		}
329
330		public void CopyToFolder(ChannelMessageHeader message, ChannelFolder folder)
331		{
332			var client = new ExchangeClient(Hostname, CredentialsProvider);
333			var messageId = client.GetMessageId(message.MessageNumber).ItemId;
334
335			client.CopyMessageToFolder(messageId, folder.FolderId);
336		}
337
338		public void RemoveFromFolder(ChannelMessageHeader message, ChannelFolder folder)
339		{
340			var client = new ExchangeClient(Hostname, CredentialsProvider);
341			var messageId = client.GetMessageId(message.MessageNumber).ItemId;
342
343			client.DeleteMessage(messageId);
344		}
345
346		public void AddLabel(ChannelMessageHeader message, string labelname)
347		{
348			var client = new ExchangeClient(Hostname, CredentialsProvider);
349			var messageId = client.GetMessageId(message.MessageNumber).ItemId;
350
351			client.CopyMessageToFolder(messageId, folders.First(f => f.Name.ToLower() == labelname.ToLower()).FolderId);
352		}
353
354		public void RemoveLabel(string messagenumber, string labelname)
355		{
356			var client = new ExchangeClient(Hostname, CredentialsProvider);
357			var messageId = client.GetMessageId(messagenumber).ItemId;
358
359			client.DeleteMessage(messageId);
360		}
361
362		public IEnumerable<ChannelContact> GetContacts()
363		{
364			var client = new ExchangeClient(Hostname, CredentialsProvider);
365
366			foreach (var contactItem in client.GetContacts())
367			{
368				if (contactItem.EmailAddresses == null || contactItem.EmailAddresses.Length == 0)
369				{
370					Logger.Warn("Contact {0} had no email address, ignoring", LogSource.Sync, contactItem.DisplayName);
371
372					continue;
373				}
374
375				var contact = new ChannelContact();
376
377				contact.Profile.ChannelProfileKey = contactItem.ItemId.Id;
378				contact.Profile.SourceAddress = new SourceAddress(contactItem.EmailAddresses[0].Value, contactItem.DisplayName);
379
380				contact.Person.Lastname = contactItem.Surname;
381				contact.Person.Firstname = contactItem.GivenName;
382
383				if (contactItem.BirthdaySpecified)
384					contact.Person.DateOfBirth = contactItem.Birthday;
385
386				contact.Profile.ScreenName = contactItem.Nickname;
387				contact.Profile.Title = contactItem.JobTitle;
388				contact.Profile.ScreenName = contactItem.DisplayName;
389				contact.Profile.CompanyName = contactItem.CompanyName;
390
391				if (contactItem.PhysicalAddresses.Length > 0)
392				{
393					contact.Profile.Street = contactItem.PhysicalAddresses[0].Street;
394					contact.Profile.ZipCode = contactItem.PhysicalAddresses[0].PostalCode;
395					contact.Profile.City = contactItem.PhysicalAddresses[0].City;
396					contact.Profile.Country = contactItem.PhysicalAddresses[0].CountryOrRegion;
397				}
398
399				yield return contact;
400			}
401		}
402
403		IClientContactsChannel IClientContactsChannel.Clone()
404		{
405			return new ExchangeClientChannel()
406				{
407					Hostname = Hostname,
408					Port = Port,
409					IsSecured = IsSecured,
410					MaxConcurrentConnections = MaxConcurrentConnections,
411					CredentialsProvider = CredentialsProvider
412				};
413		}
414    }
415}