Skip to content

Instantly share code, notes, and snippets.

@praeclarum
Created February 7, 2013 21:12
Show Gist options
  • Save praeclarum/4734210 to your computer and use it in GitHub Desktop.
Save praeclarum/4734210 to your computer and use it in GitHub Desktop.
Oh mono, you make this too easy. I was wondering if I could write an IMAP client from scratch in MonoTouch. Turns out yes, and turns out that it's easy to do!
// Authenticating [email protected]
// S: * OK Gimap ready for requests from 64.225.210.112 oi7if5386254oac.123
// C: A0001 LOGIN [email protected] ****************
// S: * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 UIDPLUS COMPRESS=DEFLATE
// S: A0001 OK [email protected] Frank Krueger authenticated (Success)
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace Inbox
{
public class ImapClient
{
public string Host { get; set; }
public int Port { get; set; }
public string Email { get; set; }
public string Password { get; set; }
int nextReqId = 1;
SslStream stream;
byte[] readBuffer;
MemoryStream responseBuffer;
public ImapClient ()
{
readBuffer = new byte[4 * 1024];
responseBuffer = new MemoryStream ();
}
public void Connect ()
{
TcpClient client = new TcpClient (Host, Port);
stream = new SslStream (
client.GetStream (),
false,
ValidateServerCertificate,
null);
Debug.WriteLine ("SSL Authenticating with " + Host);
stream.AuthenticateAsClient (Host);
BeginRead ();
Authenticate ();
}
void BeginRead ()
{
stream.BeginRead (readBuffer, 0, readBuffer.Length, OnRead, null);
}
void OnRead (IAsyncResult ar)
{
var numRead = stream.EndRead (ar);
if (numRead < 0) {
Debug.WriteLine ("Read failed with n = " + numRead + ". Reconnecting.");
Connect ();
return;
}
//
// Look for \r\n (13,10)
//
var i = 0;
while (i < numRead - 1) {
if (readBuffer[i] == 13 && readBuffer[i+1] == 10) {
//
// Got it, paste it onto responseBuffer
//
responseBuffer.Write (readBuffer, 0, i + 2);
responseBuffer.Flush ();
HandleResponse ();
//
// Begin looking for the next response
//
numRead -= (i + 2);
if (numRead > 0) {
Array.Copy (readBuffer, i + 2, readBuffer, 0, numRead);
}
i = 0;
}
else {
i++;
}
}
//
// And continue...
//
BeginRead ();
}
void HandleResponse ()
{
var data = responseBuffer.ToArray ();
var str = Encoding.UTF8.GetString (data);
Debug.WriteLine ("S: " + str);
responseBuffer.Position = 0;
responseBuffer.SetLength (0);
}
void Authenticate ()
{
Debug.WriteLine ("Authenticating " + Email);
Command ("LOGIN " + Email + " " + Password);
}
void Command (string line)
{
var realLine = string.Format ("A{0:0000} {1}\r\n", nextReqId, line);
nextReqId++;
Debug.WriteLine ("C: " + realLine);
var lineBytes = Encoding.UTF8.GetBytes (realLine);
stream.Write (lineBytes);
stream.Flush ();
}
bool ValidateServerCertificate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment