Anyone who has the original iPhone will probably tell you that it’s sitting somewhere on their desk being used as a paper weight. After all, if it doesn’t have a SIM card it’s pretty much useless, right? Every time you turn it on you get that annoying SIM card message. And when you plug it into iTunes you get the same damn message.
That is exactly what was happening with a colleague of mine. His old 2G was sitting around taking up space. Why did I care? Why would I want that paper weight!? I’ll tell you…
I transformed his old iPhone into a nice wireless device for my fiancée to use. Not only that, but because I set it up using my iTunes account, I was able to download all of my paid apps onto it. I no longer have to let her use my iPhone (my precious, precious iPhone) in order to check the weather or look at LOLCats. It’s a win-win situation, imo.
If you’ve ever wanted to share that glorious moment of beating a game, or crushing your friends’ high score, or show a friend a new app you downloaded without having them buy it first, then maybe you’ve needed to take a screenshot on your iPhone.
If you’ve read my previous article on setting up GMail on the iPhone, you are now using GMail with Google Sync. However, you might not be aware that Google Sync handles your actions on the iPhone differently than might be expected. For instance, clicking the trash button doesn’t mean that the email is getting deleted. So take a few minutes and get acquainted with what’s really happening with your email. I have provided a couple of important tips below, as well as a link to the site explaining it all.
Long story short, they are a special type of static method that can appear to be an instance method while you’re coding. Normally, if you were to create a special method that performs an operation on a string, you would do something like this:
When writing the code for my GMailPush application, I searched high and low for a C# managed POP3 client hidden in the framework somewhere. After all, C# has a managed SMTP client… so why not POP3?
In my research, I found several examples of what people were doing, but nothing was already in the framework. The examples I saw were informative, but most of them were too bloated and felt “dirty” to me. And so I sought out to create my own using the knowledge that I gained.
Without further adieu, I present my SslPopClient class:
usingSystem;usingSystem.Collections.Generic;usingSystem.Net.Sockets;usingSystem.Net.Security;usingSystem.Security.Cryptography.X509Certificates;usingSystem.IO;namespace GMailPush
{publicclass SslPopClient
{/// <summary>/// Stores the host and port we'll use to connect to/// </summary>/// <param name="host">The hostname of the pop server</param>/// <param name="port">The port the pop server listens on</param>public SslPopClient(string host, int port ){// Store the connection information for when the user logs in (see Login())
_host = host;
_port = port;}/// <summary>/// Deconstructor to clean up the client connection/// </summary>
~SslPopClient(){// Try to clean up the connection before closingthis.Disconnect();}/// <summary>/// Logs into the pop server using the USER and PASS commands/// </summary>/// <param name="username">The username to connect to the server</param>/// <param name="password">The password to connect to the server</param>publicvoid Login(string username, string password ){// Create a new socket and ssl stream
_client =new TcpClient( _host, _port );
_sslStream =new SslStream( _client.GetStream(), false, new RemoteCertificateValidationCallback( ValidateServerCertificate ), new LocalCertificateSelectionCallback( SelectLocalCertificate ));// Authenticate over the ssl stream
_sslStream.AuthenticateAsClient( _host );// Initialize our reader and writer with the ssl stream
_reader =new StreamReader( _sslStream );
_writer =new StreamWriter( _sslStream );
_writer.AutoFlush= true;// Check to see whether our connection was successfulstring response = _reader.ReadLine();if(!response.StartsWith( _success ))thrownew Exception("Server responded with error");// If we got her, we're connected!this.Connected= true;// Now we try to authenticate with USER and PASSif(!this.User( username ))thrownew Exception("Username not accepted");if(!this.Pass( password ))thrownew Exception("Password not accepted");}/// <summary>/// Safely disconnects from the pop server/// </summary>publicvoid Disconnect(){if(this.Connected){// Gracefully exit the pop3 serverthis.Quit();// Turn the connected flag off so we can't perform anything elsethis.Connected= false;// Clean up our reader and writer
_reader.Close();
_reader.Dispose();
_writer.Close();
_writer.Dispose();
_sslStream.Close();
_sslStream.Dispose();// Clean up our socket
_client.Close();
_client = null;}}/// <summary>/// Sends the USER command to the pop server/// </summary>/// <param name="username">The username to connect to the server</param>/// <returns>True for success, false for failure</returns>privatebool User(string username ){// Don't continue if we're not connected to the serverif(!this.Connected)return false;// Return the results of the USER commandreturnthis.SendCommand("USER {0}", username );}/// <summary>/// Sends the PASS command to the pop server/// </summary>/// <param name="password">The password used to connect to the server</param>/// <returns>True for success, false for failure</returns>privatebool Pass(string password ){// Don't continue if we're not connected to the serverif(!this.Connected)return false;// Return the results of the PASS commandreturnthis.SendCommand("PASS {0}", password );}/// <summary>/// Sends the QUIT command to the pop server/// </summary>/// <returns>True for success, false for failure</returns>privatebool Quit(){// Don't continue if we're not connected to the serverif(!this.Connected)return false;// Just send the QUIT command by itselfreturn(this.SendCommand("QUIT"));}/// <summary>/// Sends the STAT command on the pop server/// </summary>/// <param name="messageCount">An output variable that contains the number of messages</param>/// <param name="messageSize">An output variable that contains the size of the messages</param>/// <returns>True for success, false for failure</returns>privatebool Stat(outint messageCount, outint messageSize ){// Initialize our output variables
messageCount =-1;
messageSize =-1;// Don't continue if we're not connected to the serverif(!this.Connected)return false;// Send the STAT commandif(!this.SendCommand("STAT"))return false;// Get the response parameters (there should be 2)string[] responseRarameters = _lastResponse.Split(' ');if( responseRarameters.Length!=3)return false;// Save the response values to our output variablesstring firstParameter = responseRarameters[1];string secondParameter = responseRarameters[2];int.TryParse( firstParameter, out messageCount );int.TryParse( secondParameter, out messageSize );// If we got this far, success!return true;}/// <summary>/// Sends the TOP command to the pop server/// </summary>/// <param name="messageId">The message to call TOP for</param>/// <param name="numLines">The number of lines to receive</param>/// <param name="header">An output variable containing the headers</param>/// <param name="lines">An output variable containing the lines retrieved</param>/// <returns>True for success, false for failure</returns>privatebool Top(int messageId, int numLines, out List<string> header, out List<string> lines ){// Initialize our output variables
header =new List<string>();
lines =new List<string>();// Don't continue if we're not connected to a serverif(!this.Connected)return false;// Send the TOP commandif(!this.SendCommand("TOP {0} {1}", messageId, numLines ))return false;// Read the received data until the terminating character "."string response = _reader.ReadLine();while( response !="."){// Add each header to the output variable
header.Add( response );
response = _reader.ReadLine();}// Add all the remaining lines to the output variablefor(int i =0; i < numLines; i++)
lines.Add( _reader.ReadLine());// If we got this far, success!return true;}/// <summary>/// Sends a command to the pop server/// </summary>/// <param name="command">The command to send to the server</param>/// <param name="commandParams">Any parameters used in the command string</param>/// <returns>True for success, false for failure</returns>privatebool SendCommand(string command, paramsobject[] commandParams ){if( _writer ==null|| _reader ==null)return false;// Send the command over the ssl stream to the server
_writer.WriteLine(string.Format( command, commandParams ));// Read in the last response
_lastResponse = _reader.ReadLine();if( _lastResponse ==null)return false;// See whether it was a success message or notreturn _lastResponse.StartsWith( _success );}/// <summary>/// Validates the certificates from the server/// </summary>/// <remarks>/// Found on the MSDN forums here: /// http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/7a674196-1422-4937-90cd-628c6e3ae3d1/// </remarks>/// <param name="sender"></param>/// <param name="certificate"></param>/// <param name="chain"></param>/// <param name="sslPolicyErrors"></param>/// <returns></returns>privatebool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors ){// Successif( sslPolicyErrors == SslPolicyErrors.None)return true;// Failurereturn false;}/// <summary>/// Selects the appropritate certificate to use/// </summary>/// <remarks>/// Found on the MSDN forums here: /// http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/7a674196-1422-4937-90cd-628c6e3ae3d1/// </remarks>/// <param name="sender"></param>/// <param name="targetHost"></param>/// <param name="localCertificates"></param>/// <param name="remoteCertificate"></param>/// <param name="acceptableIssuers"></param>/// <returns></returns>private X509Certificate SelectLocalCertificate(object sender, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers ){// Check to see if there are any acceptable issuers and local certificatesif( acceptableIssuers !=null&& acceptableIssuers.Length>0&& localCertificates !=null&& localCertificates.Count>0){// Loop through the certificatesforeach( X509Certificate certificate in localCertificates ){// Check to see if this cert contains an acceptable issuerif( Array.IndexOf( acceptableIssuers, certificate.Issuer)!=-1)return certificate;}}// If there were no acceptable issuers, just return the first certificate foundif( localCertificates !=null&& localCertificates.Count>0)return localCertificates[0];// Nothing was foundreturn null;}/// <summary>/// A flag to see whether the client is connected to the server or not/// </summary>publicbool Connected { get; set;}/// <summary>/// The hostname the client will connect to/// </summary>privatestring _host;/// <summary>/// The port the client will connect on/// </summary>privateint _port;/// <summary>/// The socket that will handle the transmission to the server/// </summary>private TcpClient _client;/// <summary>/// A layer to handle SSL communication with the server/// </summary>private SslStream _sslStream;/// <summary>/// Reads data from the SSL stream/// </summary>private StreamReader _reader;/// <summary>/// Writes data to the SSL stream/// </summary>private StreamWriter _writer;/// <summary>/// A reference to the last response received from the server/// </summary>privatestring _lastResponse;/// <summary>/// A constant that represents the successful response from the pop server/// </summary>privateconststring _success ="+OK";}}
I’m excited to announce my first Google Code submission. It is a desktop application that checks your GMail account for new emails. When it finds some, it sends an sms/email to your AT&T phone number to notify you. This was created because GMail does not offer push notification on the iPhone. Here is the link: http://code.google.com/p/gmailpush/
I ran into another issue searching for virtual key constants on google. In VB6 you can reference virtual keys by using the vbKey constants (i.e, vbKeyF4, vbKeyShift). I knew there had to be a way to do this in the .Net framework without defining the constants yourself (VK_SHIFT, VK_CAPITAL), I just couldn’t find it. Luckily, I had a friend who knew the answer to this, because google came up short this time.
In order to reference virtual keys in the framework, use the static object “Keys” in the System.Windows.Forms namespace (i.e, System.Windows.Forms.Keys.Capital).
Since I had such a hard time with this control, I decided to post my findings in the hopes that I can spread the knowledge to other people having the same issues.
The task at hand was to replicate a normal multi-lined TextBox control, but be able to add some color to each line of text. In a normal TextBox, you can call the AppendText() method and the control will automatically scroll to the bottom for you. Why oh why can’t the RichTextBox be so easy?
In order to overcome this problem, I created a new class to inherit from RichTextBox. My code looks something like this:
publicclass MyRichTextBox: RichTextBox
{/// <remarks>/// This has to inherit from the RichTextBox so we can/// override some of the events to properly hide the/// caret in the desired way (to only show when selecting text)/// </remarks>public MyRichTextBox(){// Set the default property valuesthis.ReadOnly= true;this.Multiline= true;this.BackColor=System.Drawing.Color.White;this.Font=newSystem.Drawing.Font("Verdana", 10);this.Dock= DockStyle.Fill;}/// <summary>/// Override the OnTextChanged event to hide the caret/// </summary>/// <param name="e"></param>protectedoverridevoid OnTextChanged( EventArgs e ){base.OnTextChanged( e );
HideCaret(this.Handle);}/// <summary>/// An override of this event to prevent the window from system beeping/// </summary>/// <param name="e"></param>protectedoverridevoid OnKeyPress( KeyPressEventArgs e ){// Do not let anything else try to process this event
e.Handled= true;}/// <summary>/// Override the OnClick event to hide the caret/// </summary>/// <param name="e"></param>protectedoverridevoid OnClick( EventArgs e ){base.OnClick( e );
HideCaret(this.Handle);}/// <summary>/// Override the OnGotFocus event to hide the caret/// </summary>/// <param name="e"></param>protectedoverridevoid OnGotFocus( EventArgs e ){base.OnGotFocus(e);
HideCaret(this.Handle);}/// <summary>/// Hides the original function that appends text and replaces/// it with this version/// </summary>/// <remarks>/// This makes the AppendText() function more like the/// AppendText() function of a TextBox, which scrolls/// to the bottom of the text after it appends the new text/// </remarks>/// <param name="message"></param>publicvoid AppendText(string text, System.Drawing.Color color ){// The first text in the textbox can stay on the first lineif(this.Text.Length!=0)base.AppendText( Environment.NewLine);// Add our text with the specified colorthis.SelectionColor= color;this.SelectedText= text;// Now do what we need in order to scroll to the bottom and hide the caretthis.Select(this.Text.Length, 0);this.ScrollToCaret();
HideCaret(this.Handle);}/// <summary>/// A DLL import that will help us hide the caret in the RichTextBox/// </summary>/// <param name="hwnd"></param>/// <returns></returns>[DllImport("user32.dll", EntryPoint ="HideCaret")]privatestaticexternbool HideCaret( IntPtr hwnd );}