Merge pull request #3626 from lateralusX/jlorenss/win-api-family-support-eglib
[mono.git] / mcs / class / System / System.Net.Mail / MailMessage.cs
index c45ac4e9283727196ba8158310ff8eb5b318a93c..b5a58d86b8160caadfdf41d028408ffe441e0983 100644 (file)
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-#if NET_2_0
-
 using System.Collections.Specialized;
 using System.Globalization;
 using System.Net.Mime;
 using System.Text;
 
 namespace System.Net.Mail {
-       [MonoTODO]
        public class MailMessage : IDisposable
        {
                #region Fields
@@ -44,58 +41,71 @@ namespace System.Net.Mail {
                AlternateViewCollection alternateViews;
                AttachmentCollection attachments;
                MailAddressCollection bcc;
+               MailAddressCollection replyTo;          
                string body;
                MailPriority priority;
-               MailAddress replyTo, sender;
+               MailAddress sender;
                DeliveryNotificationOptions deliveryNotificationOptions;
                MailAddressCollection cc;
                MailAddress from;
                NameValueCollection headers;
                MailAddressCollection to;
                string subject;
-               Encoding subjectEncoding;
-               ContentType bodyContentType;
+               Encoding subjectEncoding, bodyEncoding, headersEncoding = Encoding.UTF8;
+               bool isHtml;
 
                #endregion // Fields
 
                #region Constructors
 
-               public MailMessage ()
-               {
-               }
-
-               [MonoTODO ("FormatException")]
-               public MailMessage (MailAddress from, MailAddress to)
-               {
-                       if (from == null || to == null)
-                               throw new ArgumentNullException ();
-                       
-                       From = from;
-
+               public MailMessage () {
                        this.to = new MailAddressCollection ();
-                       this.to.Add (to);
 
                        alternateViews = new AlternateViewCollection ();
                        attachments = new AttachmentCollection ();
                        bcc = new MailAddressCollection ();
                        cc = new MailAddressCollection ();
+                       replyTo = new MailAddressCollection ();
                        headers = new NameValueCollection ();
 
                        headers.Add ("MIME-Version", "1.0");
                }
 
-               public MailMessage (string from, string to)
-                       : this (new MailAddress (from), new MailAddress (to))
+               // FIXME: should it throw a FormatException if the addresses are wrong? 
+               // (How is it possible to instantiate such a malformed MailAddress?)
+               public MailMessage (MailAddress from, MailAddress to) : this ()
                {
                        if (from == null || to == null)
                                throw new ArgumentNullException ();
+
+                       From = from;
+
+                       this.to.Add (to);
                }
 
-               public MailMessage (string from, string to, string subject, string body)
-                       : this (new MailAddress (from), new MailAddress (to))
+               public MailMessage (string from, string to) : this ()
                {
-                       if (from == null || to == null)
-                               throw new ArgumentNullException ();
+                       if (from == null || from == String.Empty)
+                               throw new ArgumentNullException ("from");
+                       if (to == null || to == String.Empty)
+                               throw new ArgumentNullException ("to");
+                       
+                       this.from = new MailAddress (from);
+                       foreach (string recipient in to.Split (new char [] {','}))
+                               this.to.Add (new MailAddress (recipient.Trim ()));
+               }
+
+               public MailMessage (string from, string to, string subject, string body) : this ()
+               {
+                       if (from == null || from == String.Empty)
+                               throw new ArgumentNullException ("from");
+                       if (to == null || to == String.Empty)
+                               throw new ArgumentNullException ("to");
+                       
+                       this.from = new MailAddress (from);
+                       foreach (string recipient in to.Split (new char [] {','}))
+                               this.to.Add (new MailAddress (recipient.Trim ()));
+
                        Body = body;
                        Subject = subject;
                }
@@ -118,20 +128,34 @@ namespace System.Net.Mail {
 
                public string Body {
                        get { return body; }
-                       set { body = value; }
+                       set {
+                               // autodetect suitable body encoding (ASCII or UTF-8), if it is not initialized yet.
+                               if (value != null && bodyEncoding == null)
+                                       bodyEncoding = GuessEncoding (value) ?? Encoding.ASCII;
+                               body = value;
+                       }
                }
 
                internal ContentType BodyContentType {
                        get {
-                               if (bodyContentType == null)
-                                       bodyContentType = new ContentType ("text/plain; charset=us-ascii");
-                               return bodyContentType;
+                               ContentType ct = new ContentType (isHtml ? "text/html" : "text/plain");
+                               ct.CharSet = (BodyEncoding ?? Encoding.ASCII).HeaderName;
+                               return ct;
                        }
                }
 
+               internal TransferEncoding ContentTransferEncoding {
+                       get { return GuessTransferEncoding (BodyEncoding); }
+               }
+
                public Encoding BodyEncoding {
-                       get { return Encoding.GetEncoding (BodyContentType.CharSet); }
-                       set { BodyContentType.CharSet = value.WebName; }
+                       get { return bodyEncoding; }
+                       set { bodyEncoding = value; }
+               }
+
+               public TransferEncoding BodyTransferEncoding {
+                       get { return GuessTransferEncoding (BodyEncoding); }
+                       set { throw new NotImplementedException (); }
                }
 
                public MailAddressCollection CC {
@@ -153,13 +177,8 @@ namespace System.Net.Mail {
                }
 
                public bool IsBodyHtml {
-                       get { return String.Compare (BodyContentType.MediaType, "text/html", true, CultureInfo.InvariantCulture) == 0; }
-                       set {
-                               if (value)
-                                       BodyContentType.MediaType = "text/html";
-                               else
-                                       BodyContentType.MediaType = "text/plain";
-                       }
+                       get { return isHtml; }
+                       set { isHtml = value; }
                }
 
                public MailPriority Priority {
@@ -167,9 +186,28 @@ namespace System.Net.Mail {
                        set { priority = value; }
                }
 
-               public MailAddress ReplyTo {
+               public
+               Encoding HeadersEncoding {
+                       get { return headersEncoding; }
+                       set { headersEncoding = value; } 
+               }
+
+               public
+               MailAddressCollection ReplyToList {
                        get { return replyTo; }
-                       set { replyTo = value; }
+               }
+
+               [Obsolete ("Use ReplyToList instead")]
+               public MailAddress ReplyTo {
+                       get {
+                               if (replyTo.Count == 0)
+                                       return null;
+                               return replyTo [0];
+                       }
+                       set {
+                               replyTo.Clear ();
+                               replyTo.Add (value);
+                       }
                }
 
                public MailAddress Sender {
@@ -179,7 +217,11 @@ namespace System.Net.Mail {
 
                public string Subject {
                        get { return subject; }
-                       set { subject = value; }
+                       set {
+                               if (value != null && subjectEncoding == null)
+                                       subjectEncoding = GuessEncoding (value);
+                               subject = value;
+                       }
                }
 
                public Encoding SubjectEncoding {
@@ -205,8 +247,66 @@ namespace System.Net.Mail {
                {
                }
 
+               private Encoding GuessEncoding (string s)
+               {
+                       for (int i = 0; i < s.Length; i++)
+                               if (s [i] >= '\u0080')
+                                       return UTF8Unmarked;
+                       return null;
+               }
+
+               internal static TransferEncoding GuessTransferEncoding (Encoding enc)
+               {
+                       if (Encoding.ASCII.Equals (enc))
+                               return TransferEncoding.SevenBit;
+                       else if (Encoding.UTF8.CodePage == enc.CodePage ||
+#if !MOBILE
+                           Encoding.Unicode.CodePage == enc.CodePage || Encoding.UTF32.CodePage == enc.CodePage
+#else
+                           Encoding.Unicode.CodePage == enc.CodePage
+#endif
+                                        )
+                               return TransferEncoding.Base64;
+                       else
+                               return TransferEncoding.QuotedPrintable;
+               }
+
+               static char [] hex = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+               internal static string To2047(byte [] bytes)
+               {
+                       StringBuilder sb = new StringBuilder ();
+                       foreach (byte i in bytes) {
+                               if (i < 0x21 || i > 0x7E || i == '?' || i == '=' || i == '_') {
+                                       sb.Append ('=');
+                                       sb.Append (hex [(i >> 4) & 0x0f]);
+                                       sb.Append (hex [i & 0x0f]);
+                               } else
+                                       sb.Append ((char) i);
+                       }
+                       return sb.ToString ();
+               }
+
+               internal static string EncodeSubjectRFC2047 (string s, Encoding enc)
+               {
+                       if (s == null || Encoding.ASCII.Equals (enc))
+                               return s;
+                       for (int i = 0; i < s.Length; i++)
+                               if (s [i] >= '\u0080') {
+                                       string quoted = To2047(enc.GetBytes (s));
+                                       return String.Concat ("=?", enc.HeaderName, "?Q?", quoted, "?=");
+                               }
+                       return s;
+               }
+
+               static Encoding utf8unmarked;
+               static Encoding UTF8Unmarked {
+                       get {
+                               if (utf8unmarked == null)
+                                       utf8unmarked = new UTF8Encoding (false);
+                               return utf8unmarked;
+                       }
+               }
                #endregion // Methods
        }
 }
 
-#endif // NET_2_0