Using Idle

Jul 3, 2012 at 2:57 PM

Hi,

I got a question about how to implement Idle.
I tried a simple example in which I create an ImapClient and connect, fetch some messages from the Inbox and return the model to the view. 

When I just call client.StartIdle() the Thread freezes and I'll never see the view.

So I thought I would handle idle in a seperate thread, but this gives me an error.

The error I get is: The Read method cannot be called when another read operation is pending.

This is my code:

 

// Select a mailbox
var mailbox = client.Select("Inbox");

// Idle in a seperate thread
if (client.ServerCapability.IsIdleSupported)
{
	var idle = new Idle(client);
	var thread = new Thread(idle.Activate);
	thread.Start();
}

// Fetch messages
var messages = client.Messages.Where(x => x.Date < DateTime.Now).Select(x => x.Envelope);

// return view
View(messages);

In the Idle.Activate I used the code as described in the Establishing and using an IDLE connection from the documentation.

How can I run Idle in the background and keep working?

Thanks in advance!

Coordinator
Jul 3, 2012 at 6:12 PM

Hi,

if you want to use IDLE, you will need to use it in a seperate thread, since the IDLE method is blocking.

Your error probably comes from the attempt to use the idling connection for something else, while its idling.

For reusing the connection you need to stop idling, do your thing and start idling again.

To interrupt an active IDLE connection you need to call StopIdle from a different thread than the blocked one.

Hope this cleares things up.

Alexnander

Jul 4, 2012 at 8:29 AM
Edited Jul 4, 2012 at 8:29 AM

Hi Alexander,

Thanks for your reply, much appreciated!

Yes, it makes sense. I use IDLE in a seperate thread, but in my code example above I'm fetching messages after enabling IDLE, which probably causes the error.

I still get the error if I call StopIdleAsync(), but sometimes I do get the messages, so I think I'm missing something.

The easiest way to make it work is to create a seperate connection for IDLE, but I'm not sure if that's the way to go.

Coordinator
Jul 8, 2012 at 8:21 PM

Without seeing your code I can't really help, you justneed to make sure you call the StopIdle method from a different thread than the blocked one.

Alexander

Jul 9, 2012 at 2:38 PM
Edited Jul 9, 2012 at 2:43 PM

I modified the code and tried to figure it out myself, but I cannot succeed. I keep getting the same error message.
I start the idling process in a seperate thread to prevent UI freeze and stop idling in a seperate thread.

The part where I start idling, do a thread sleep and the stop idle right after eachother is just the test the starting and stopping. I doesn't make sense in this code example because nothing happens after starting and before stopping, but it would if I would start a connection only and provide a button users could push to retrieve messages. In that case I should stop idling first and then retrieve messages using the same client.

Not sure if it matters in this case, but I'm using the library in an MVC3 web project.

This is my code:

 

public ActionResult Index()
{
	// Create client and connect to server
	var imapClient = new ImapClient { Security = SecurityPolicies.Explicit };
	imapClient.Connect("imap.gmail.com", 993);
	imapClient.Authenticate("emailaddress@gmail.com", "password", SaslMechanics.Login);

	// Select a mailbox
	imapClient.Select("INBOX");

	// Start idle
	StartIdle(imapClient);

	Thread.Sleep(5000);

	// Stopping idle
	StopIdle(imapClient);

	// Retrieve messages
	var messages = imapClient.Messages.Where(x => x.Date < DateTime.Now).Select(x => x.Envelope).AsEnumerable();
	messages = messages.OrderByDescending(x => x.Date);

	// Starting idle again
	StartIdle(imapClient);

	// Return Index view
    return View(messages);
}

// Start idle in seperate thread to prevent UI freeze
private void StartIdle(ImapClient imapClient)
{
	new Thread(() =>
	{
		if (imapClient.ServerCapability.IsIdleSupported)
		{
			imapClient.StatusUpdateReceived += OnStatusUpdateReceived;
			imapClient.StartIdle();
		}
	})
	.Start();
}

// Stopping idle in a seperate thread
private void StopIdle(ImapClient imapClient)
{
	new Thread(() =>
	{
	    if (imapClient.ServerCapability.IsIdleSupported)
	    {
	        imapClient.StatusUpdateReceived -= OnStatusUpdateReceived;
	        imapClient.StopIdleAsync();
	    }
	})
	.Start();
}

// Idle status update received event handler
private static void OnStatusUpdateReceived(object sender, StatusUpdateReceivedEventArgs e)
{
	var client = sender as ImapClient;
	if (client == null)
		return;
}

Aug 15, 2012 at 11:37 AM

Hi, 

I'm sorry for not answering sooner, I was quite busy last month, I will wrap up some sample code and post it here, if its still desirable.

Alex

Aug 17, 2012 at 12:18 PM

Hi Alex,

No problem at all! I understand that you have other priorities.

I would appreciate it if you can provide some sample code.

Thanks in advance!

Jeff