Created
February 7, 2013 21:12
-
-
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!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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