0

Visible Reality at Schmooze Fair

by Bill Forney 17. April 2009 21:34

On Thursday Visible Reality had a booth at Schmooze Fair. It was lots of fun introducing people to our new company and showing off our development skills with our weekend project, the Wii-mote and USB rocket launcher game. Vida took some photos of our booth too. Hopefully everyone who dropped by enjoyed it too.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Tags: ,

Technology | Visible Reality

0

A better direct SMTP mailer

by Bill Forney 12. April 2009 12:51

Wayne posted an interesting little SMTP snippet recently and I had been poking around at that, so I thought I'd share this... It is an adaptation of several articles scattered around through the years, his code, and several other things I wrote a while ago. Enjoy...

namespace SMTP
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.IO;
    using System.Net;
    using System.Net.Mail;
    using System.Net.Sockets;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Threading;

    /// <summary>
    /// provides methods to send email via smtp direct to mail server
    /// </summary>
    public class SmtpDirect
    {
        /// <summary>
        /// Determines whether the specified input email is email.
        /// </summary>
        /// <param name="inputEmail">The input email.</param>
        /// <param name="fromEmail">From email.</param>
        /// <param name="tryLookup">if set to <c>true</c> [try lookup].</param>
        /// <param name="tryConnect">if set to <c>true</c> [try connect].</param>
        /// <returns>
        ///     <c>true</c> if the specified input email is email; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsEmail(string inputEmail, string fromEmail, bool tryLookup, bool tryConnect)
        {
            // WLF: Check for null or empty input

            if (string.IsNullOrEmpty(inputEmail))
            {
                return false;
            }

            // WLF: RegEx check

            const string strRegex = @"^(([a-zA-Z0-9_\-\+/\^]+)([\.]?)([a-zA-Z0-9_\-\+/\^]+))+@((\[[0-9]{1,3}" +
                                    @"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" +
                                    @".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
            var re = new Regex(strRegex);

            if (!re.IsMatch(inputEmail))
            {
                return false;
            }

            // WWB: Check To Make Sure The Email Address Parses

            MailAddress mailAddress;
            try
            {
                mailAddress = new MailAddress(inputEmail);
            }
            catch
            {
                return false;
            }

            if (tryLookup)
            {
                // WWB: Check To Make Sure There Is a SMTP Server To Recieve The Email Address

                if (DnsMx.GetMXRecords(mailAddress.Host).Length == 0)
                {
                    return false;
                }
            }

            if (tryConnect)
            {
                // WLF: Try to connect to the SMTP server

                try
                {
                    var mxRecords = DnsMx.GetMXRecords(mailAddress.Host);
                    if (mxRecords.Length == 0)
                    {
                        return false;
                    }

                    var ipHostEntry = Dns.GetHostEntry(mxRecords[0]);
                    var endPoint = new IPEndPoint(ipHostEntry.AddressList[0], 25);
                    var s = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                    s.Connect(endPoint);

                    // WLF: Attempting to connect

                    if (!CheckResponse(s, SmtpResponse.ConnectSuccess))
                    {
                        s.Close();
                        return false;
                    }

                    // WLF: HELO server

                    Senddata(s, string.Format("HELO {0}\r\n", Dns.GetHostName()));
                    if (!CheckResponse(s, SmtpResponse.GenericSuccess))
                    {
                        s.Close();
                        return false;
                    }

                    // WLF: Say who it is from 

                    Senddata(s, string.Format("MAIL From: {0}\r\n", fromEmail));
                    if (!CheckResponse(s, SmtpResponse.GenericSuccess))
                    {
                        s.Close();
                        return false;
                    }

                    // WLF: Try to send 

                    Senddata(s, string.Format("RCPT TO: {0}\r\n", inputEmail));
                    if (!CheckResponse(s, SmtpResponse.GenericSuccess))
                    {
                        s.Close();
                        return false;
                    }
                }
                catch
                {
                    return false;
                }
            }

            // WWB: Success

            return true;
        }

        /// <summary>
        /// Sends the mail directly to the receiver's server.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="errors">The errors.</param>
        /// <returns></returns>
        public static bool SendDirect(MailMessage message, out List<string> errors)
        {
            errors = new List<string>();
            var deliveryAddresses = new List<MailAddress>();

            // WLF: Add To's
            foreach (var address in message.To)
            {
                deliveryAddresses.Add(address);
            }

            // WLF: Add CC's
            foreach (var address in message.CC)
            {
                deliveryAddresses.Add(address);
            }

            foreach (var to in deliveryAddresses)
            {
                var mxRecords = DnsMx.GetMXRecords(to.Host);
                if (mxRecords.Length == 0)
                {
                    errors.Add(to.Host);
                }
                else
                {
                    var ipHostEntry = Dns.GetHostEntry(mxRecords[0]);
                    var endPoint = new IPEndPoint(ipHostEntry.AddressList[0], 25);
                    var s = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                    s.Connect(endPoint);

                    if (!CheckResponse(s, SmtpResponse.ConnectSuccess))
                    {
                        s.Close();
                        return false;
                    }

                    Senddata(s, string.Format("HELO {0}\r\n", Dns.GetHostName()));
                    if (!CheckResponse(s, SmtpResponse.GenericSuccess))
                    {
                        s.Close();
                        return false;
                    }

                    Senddata(s, string.Format("MAIL From: {0}\r\n", message.From));
                    if (!CheckResponse(s, SmtpResponse.GenericSuccess))
                    {
                        s.Close();
                        return false;
                    }

                    Senddata(s, string.Format("RCPT TO: {0}\r\n", to.Address));
                    if (!CheckResponse(s, SmtpResponse.GenericSuccess))
                    {
                        s.Close();
                        return false;
                    }

                    #region Build message body

                    var header = GetHeader(message);

                    var msgBody = message.Body;
                    if (!msgBody.EndsWith("\r\n"))
                        msgBody += "\r\n";

                    #region Handle attachments

                    if (message.Attachments.Count > 0)
                    {
                        header.Append("MIME-Version: 1.0\r\n");
                        header.Append("Content-Type: multipart/mixed; boundary=unique-boundary-1\r\n");
                        header.Append("\r\n");
                        header.Append("This is a multi-part message in MIME format.\r\n");
                        var sb = new StringBuilder();
                        sb.Append("--unique-boundary-1\r\n");
                        sb.Append("Content-Type: text/plain\r\n");
                        sb.Append("Content-Transfer-Encoding: 7Bit\r\n");
                        sb.Append("\r\n");
                        sb.Append(msgBody + "\r\n");
                        sb.Append("\r\n");

                        foreach (var a in message.Attachments)
                        {
                            if (a == null) continue;

                            var f = new FileInfo(a.Name);
                            sb.Append("--unique-boundary-1\r\n");
                            sb.Append("Content-Type: application/octet-stream; file=" + f.Name + "\r\n");
                            sb.Append("Content-Transfer-Encoding: base64\r\n");
                            sb.Append("Content-Disposition: attachment; filename=" + f.Name + "\r\n");
                            sb.Append("\r\n");
                            var fs = f.OpenRead();
                            var binaryData = new Byte[fs.Length];
                            long bytesRead = fs.Read(binaryData, 0, (int) fs.Length);
                            Trace.WriteLine(string.Format("Bytes read: {0}", bytesRead));
                            fs.Close();
                            var base64String = Convert.ToBase64String(binaryData, 0, binaryData.Length);

                            for (var i = 0; i < base64String.Length;)
                            {
                                var nextchunk = 100;
                                if (base64String.Length - (i + nextchunk) < 0)
                                    nextchunk = base64String.Length - i;
                                sb.Append(base64String.Substring(i, nextchunk));
                                sb.Append("\r\n");
                                i += nextchunk;
                            }
                            sb.Append("\r\n");
                        }

                        msgBody = sb.ToString();
                    }

                    #endregion

                    #endregion

                    #region Send message body

                    Senddata(s, ("DATA\r\n"));
                    if (!CheckResponse(s, SmtpResponse.DataSuccess))
                    {
                        s.Close();
                        return false;
                    }
                    header.Append("\r\n");
                    header.Append(msgBody);
                    header.Append(".\r\n");
                    header.Append("\r\n");
                    header.Append("\r\n");
                    Senddata(s, header.ToString());
                    if (!CheckResponse(s, SmtpResponse.GenericSuccess))
                    {
                        s.Close();
                        return false;
                    }

                    Senddata(s, "QUIT\r\n");
                    CheckResponse(s, SmtpResponse.QuitSuccess);
                    s.Close();

                    #endregion
                }
            }

            return errors.Count == 0;
        }

        /// <summary>
        /// Sends the specified message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="outboundSmtpServer">The outbound SMTP server.</param>
        /// <returns></returns>
        public static bool Send(MailMessage message, string outboundSmtpServer)
        {
            var ipHostEntry = Dns.GetHostEntry(outboundSmtpServer);
            var endPoint = new IPEndPoint(ipHostEntry.AddressList[0], 25);
            var s = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            s.Connect(endPoint);

            if (!CheckResponse(s, SmtpResponse.ConnectSuccess))
            {
                s.Close();
                return false;
            }

            Senddata(s, string.Format("HELO {0}\r\n", Dns.GetHostName()));
            if (!CheckResponse(s, SmtpResponse.GenericSuccess))
            {
                s.Close();
                return false;
            }

            Senddata(s, string.Format("MAIL From: {0}\r\n", message.From));
            if (!CheckResponse(s, SmtpResponse.GenericSuccess))
            {
                s.Close();
                return false;
            }

            foreach (var to in message.To)
            {
                Senddata(s, string.Format("RCPT TO: {0}\r\n", to.Address));
                if (!CheckResponse(s, SmtpResponse.GenericSuccess))
                {
                    s.Close();
                    return false;
                }
            }

            foreach (var cc in message.CC)
            {
                Senddata(s, string.Format("RCPT TO: {0}\r\n", cc.Address));
                if (!CheckResponse(s, SmtpResponse.GenericSuccess))
                {
                    s.Close();
                    return false;
                }
            }

            var header = GetHeader(message);

            var msgBody = message.Body;
            if (!msgBody.EndsWith("\r\n"))
                msgBody += "\r\n";

            #region Handle attachments

            if (message.Attachments.Count > 0)
            {
                header.Append("MIME-Version: 1.0\r\n");
                header.Append("Content-Type: multipart/mixed; boundary=unique-boundary-1\r\n");
                header.Append("\r\n");
                header.Append("This is a multi-part message in MIME format.\r\n");
                var sb = new StringBuilder();
                sb.Append("--unique-boundary-1\r\n");
                sb.Append("Content-Type: text/plain\r\n");
                sb.Append("Content-Transfer-Encoding: 7Bit\r\n");
                sb.Append("\r\n");
                sb.Append(msgBody + "\r\n");
                sb.Append("\r\n");

                foreach (var a in message.Attachments)
                {
                    if (a == null) continue;

                    var f = new FileInfo(a.Name);
                    sb.Append("--unique-boundary-1\r\n");
                    sb.Append("Content-Type: application/octet-stream; file=" + f.Name + "\r\n");
                    sb.Append("Content-Transfer-Encoding: base64\r\n");
                    sb.Append("Content-Disposition: attachment; filename=" + f.Name + "\r\n");
                    sb.Append("\r\n");
                    var fs = f.OpenRead();
                    var binaryData = new Byte[fs.Length];
                    long bytesRead = fs.Read(binaryData, 0, (int) fs.Length);
                    Trace.WriteLine(string.Format("Bytes read: {0}", bytesRead));
                    fs.Close();
                    var base64String = Convert.ToBase64String(binaryData, 0, binaryData.Length);

                    for (var i = 0; i < base64String.Length;)
                    {
                        var nextchunk = 100;
                        if (base64String.Length - (i + nextchunk) < 0)
                            nextchunk = base64String.Length - i;
                        sb.Append(base64String.Substring(i, nextchunk));
                        sb.Append("\r\n");
                        i += nextchunk;
                    }
                    sb.Append("\r\n");
                }

                msgBody = sb.ToString();
            }

            #endregion

            Senddata(s, ("DATA\r\n"));
            if (!CheckResponse(s, SmtpResponse.DataSuccess))
            {
                s.Close();
                return false;
            }
            header.Append("\r\n");
            header.Append(msgBody);
            header.Append(".\r\n");
            header.Append("\r\n");
            header.Append("\r\n");
            Senddata(s, header.ToString());
            if (!CheckResponse(s, SmtpResponse.GenericSuccess))
            {
                s.Close();
                return false;
            }

            Senddata(s, "QUIT\r\n");
            CheckResponse(s, SmtpResponse.QuitSuccess);
            s.Close();
            return true;
        }

        /// <summary>
        /// Gets the header.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns></returns>
        private static StringBuilder GetHeader(MailMessage message)
        {
            var header = new StringBuilder();

            header.Append("From: " + message.From + "\r\n");

            var tos = string.Empty;
            foreach (var to in message.To)
            {
                tos = to.Address + ",";
            }
            header.AppendFormat("To: {0}\r\n", tos.TrimEnd(','));

            if (message.CC.Count > 0)
            {
                var ccs = string.Empty;
                foreach (var cc in message.CC)
                {
                    ccs = cc.Address + ",";
                }
                header.AppendFormat("Cc: {0}\r\n", ccs.TrimEnd(','));
            }

            header.AppendFormat("Date: {0}\r\n", DateTime.Now.ToString("ddd, d M y H:m:s z"));
            header.AppendFormat("Subject: {0}\r\n", message.Subject);
            header.Append("X-Mailer: SMTPDirect v1\r\n");
            return header;
        }

        #region Socket Operations

        /// <summary>
        /// Sends data to the specified socket.
        /// </summary>
        /// <param name="socket">The socket.</param>
        /// <param name="message">The message.</param>
        private static void Senddata(Socket socket, string message)
        {
            var messageBytes = Encoding.ASCII.GetBytes(message);
            socket.Send(messageBytes, 0, messageBytes.Length, SocketFlags.None);
        }

        /// <summary>
        /// Checks the response.
        /// </summary>
        /// <param name="socket">The socket.</param>
        /// <param name="responseExpected">The response expected.</param>
        /// <returns></returns>
        private static bool CheckResponse(Socket socket, SmtpResponse responseExpected)
        {
            var bytes = new byte[1024];
            while (socket.Available == 0)
            {
                Thread.Sleep(100);
            }

            socket.Receive(bytes, 0, socket.Available, SocketFlags.None);
            var sResponse = Encoding.ASCII.GetString(bytes);
            var response = Convert.ToInt32(sResponse.Substring(0, 3));
            return response == (int) responseExpected;
        }

        #endregion

        #region DNS

        /// <summary>
        /// DNS MX Lookup
        /// </summary>
        public class DnsMx
        {
            /// <summary>
            /// Executes a DNS Query
            /// </summary>
            /// <param name="pszName">Name of the PSZ.</param>
            /// <param name="wType">Type of the query.</param>
            /// <param name="options">The query options.</param>
            /// <param name="aipServers">The aip servers.</param>
            /// <param name="ppQueryResults">The pp query results.</param>
            /// <param name="pReserved">The p reserved.</param>
            /// <returns></returns>
            [DllImport("dnsapi", EntryPoint = "DnsQuery_W", CharSet = CharSet.Unicode, SetLastError = true,
                ExactSpelling = true)]
            private static extern int DnsQuery([MarshalAs(UnmanagedType.VBByRefStr)] ref string pszName,
                                               QueryTypes wType, QueryOptions options, int aipServers,
                                               ref IntPtr ppQueryResults, int pReserved);

            /// <summary>
            /// Grabs the DNS Record List
            /// </summary>
            /// <param name="pRecordList">The p record list.</param>
            /// <param name="FreeType">Type of the free.</param>
            [DllImport("dnsapi", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern void DnsRecordListFree(IntPtr pRecordList, int FreeType);

            /// <summary>
            /// Gets the MX records.
            /// </summary>
            /// <param name="domain">The domain.</param>
            /// <returns></returns>
            public static string[] GetMXRecords(string domain)
            {
                var ptr1 = IntPtr.Zero;
                IntPtr ptr2;
                MXRecord recMx;

                if (Environment.OSVersion.Platform != PlatformID.Win32NT)
                {
                    throw new NotSupportedException();
                }

                var list1 = new List<string>();
                var num1 = DnsQuery(ref domain, QueryTypes.DnsTypeMX, QueryOptions.DnsQueryBypassCache, 0, ref ptr1, 0);

                if (num1 != 0)
                {
                    throw new Win32Exception(num1);
                }

                for (ptr2 = ptr1; !ptr2.Equals(IntPtr.Zero); ptr2 = recMx.PNext)
                {
                    recMx = (MXRecord) Marshal.PtrToStructure(ptr2, typeof (MXRecord));
                    if (recMx.WType != 15) continue;

                    var text1 = Marshal.PtrToStringAuto(recMx.PNameExchange);
                    list1.Add(text1);
                }

                DnsRecordListFree(ptr1, 0);
                return list1.ToArray();
            }

            #region Nested type: MXRecord

            [StructLayout(LayoutKind.Sequential)]
            private struct MXRecord
            {
                public IntPtr PNext;
                public string PName;
                public short WType;
                public short WDataLength;
                public int Flags;
                public int DwTtl;
                public int DwReserved;
                public IntPtr PNameExchange;
                public short WPreference;
                public short Pad;
            }

            #endregion

            #region Nested type: QueryOptions

            /// <summary>
            /// Query Options
            /// </summary>
            private enum QueryOptions
            {
                //DnsQueryAcceptTruncatedResponse = 1,
                /// <summary>
                /// DNS Query Bypass Cache
                /// </summary>
                DnsQueryBypassCache = 8,
                //DnsQueryDontResetTtlValues = 0x100000,
                //DnsQueryNoHostsFile = 0x40,
                //DnsQueryNoLocalName = 0x20,
                //DnsQueryNoNetbt = 0x80,
                //DnsQueryNoRecursion = 4,
                //DnsQueryNoWireQuery = 0x10,
                //DnsQueryReserved = -16777216,
                //DnsQueryReturnMessage = 0x200,
                //DnsQueryStandard = 0,
                //DnsQueryTreatAsFqdn = 0x1000,
                //DnsQueryUseTcpOnly = 2,
                //DnsQueryWireOnly = 0x100
            }

            #endregion

            #region Nested type: QueryTypes

            /// <summary>
            /// Query Types
            /// </summary>
            private enum QueryTypes
            {
                //DnsTypeA = 1,
                //DnsTypeNs = 2,
                //DnsTypeCname = 5,
                //DnsTypeSoa = 6,
                //DnsTypePtr = 12,
                //DnsTypeHinfo = 13,
                /// <summary>
                /// DNS Type MX
                /// </summary>
                DnsTypeMX = 15,
                //DnsTypeTxt = 16,
                //DnsTypeAaaa = 28
            }

            #endregion
        }

        #endregion

        #region Nested type: SmtpResponse

        /// <summary>
        /// Smtp Response
        /// </summary>
        private enum SmtpResponse
        {
            /// <summary>
            /// Connect Success
            /// </summary>
            ConnectSuccess = 220,
            /// <summary>
            /// Generic Success
            /// </summary>
            GenericSuccess = 250,
            /// <summary>
            /// Data Success
            /// </summary>
            DataSuccess = 354,
            /// <summary>
            /// Quit Success
            /// </summary>
            QuitSuccess = 221
        }

        #endregion
    }
}

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Tags: , , , ,

Software Development | Technology

0

New Flickr Photo Gallery

by Bill Forney 29. March 2009 15:00

I was feeling industrious today so I added a new Silverlight photo gallery to my blog. There is a link on the home page for it or you can click this.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Tags: ,

Blog | Technology | Silverlight

0

My Seagate issues...

by Bill Forney 22. March 2009 18:00

As with all technology, when it works it's great, when it doesn't it is really, really bad. Seagate lately has had a batch of hard drives released that have had issues with their firmware. They announced this after I had gone through about five of them, and some customers of mine had gone through two or three more. Since they're under warranty I can have them replaced, but I won't get back my time rebuilding my RAID array and those of my customers. Because of this, I have switched to Western Digital for my future hard drives and those I recommend. The new drives run in SATA generation 2 instead of 1 out of the box, they seem to be faster, and I haven't had any issues with them.

The main reason I had stuck with Seagate for so long was their warranty of 5 years, but now that WD has that too I can switch away without worry. The issue, my friends and I think, is the substandard manufacturing plants that Maxtor had. Seagate bought Maxtor a while ago and we all knew at the time that Maxtor sucked. The sheer volume of Maxtor drives going through my friend's shop for repair (i.e. replacement) was proof enough of that.

I have kept an eye on the new SSD's (solid state disks) that are creeping down in price. The good ones are still very expensive, but in another year or so things are going to start shifting away from the old hard drives. I look forward to the speed boost that should bring.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Tags: , ,

Technology

Powered by BlogEngine.NET 1.6.1.0
Original Design by Laptop Geek, Adapted by onesoft