BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[mono.git] / mcs / class / System / System.Net.Mime / ContentDisposition.cs
1 //
2 // System.Net.Mime.ContentDisposition.cs
3 //
4 // Authors:
5 //      Tim Coleman (tim@timcoleman.com)
6 //      John Luke (john.luke@gmail.com)
7 //
8 // Copyright (C) Tim Coleman, 2004
9 // Copyright (C) John Luke, 2005
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 #if NET_2_0
34
35 using System.Text;
36 using System.Collections;
37 using System.Collections.Specialized;
38 using System.Globalization;
39
40 namespace System.Net.Mime {
41         public class ContentDisposition
42         {
43                 // FIXME: "r" was not enough, neither was zzz
44                 // so this will fail if the offset is not an even hour
45                 const string rfc822 = "dd MMM yyyy HH':'mm':'ss zz00";
46                 
47                 #region Fields
48
49                 string dispositionType;
50                 StringDictionary parameters = new StringDictionary ();
51
52                 #endregion // Fields
53
54                 #region Constructors
55
56                 public ContentDisposition () : this (DispositionTypeNames.Attachment)
57                 {
58                 }
59
60                 public ContentDisposition (string disposition)
61                 {
62                         if (disposition == null)
63                                 throw new ArgumentNullException ();
64                         if (disposition.Length < 1)
65                                 throw new FormatException ();
66                         Size = -1;
67
68                         try {
69                                 int index = disposition.IndexOf (';');
70                                 if (index < 0) {
71                                         dispositionType = disposition.Trim ();
72                                 }
73                                 else {
74                                         string[] split = disposition.Split (';');
75                                         dispositionType = split[0].Trim ();
76                                         for (int i = 1; i < split.Length; i++)
77                                                 Parse (split[i]);
78                                 }
79                         } catch {
80                                 throw new FormatException ();
81                         }
82                 }
83
84                 // the individual pieces
85                 void Parse (string pair)
86                 {
87                         if (pair == null || pair.Length < 0)
88                                 return;
89
90                         string[] split = pair.Split ('=');
91                         if (split.Length == 2)
92                                 parameters.Add (split[0].Trim (), split[1].Trim ());
93                         else
94                                 throw new FormatException ();
95                 }
96
97                 #endregion // Constructors
98
99                 #region Properties
100
101                 public DateTime CreationDate {
102                         get {
103                                 if (parameters.ContainsKey ("creation-date"))
104                                         return DateTime.ParseExact (parameters["creation-date"], rfc822, null);
105                                 else
106                                         return DateTime.MinValue;
107                         }
108                         set {
109                                 if (value > DateTime.MinValue)
110                                         parameters["creation-date"] = value.ToString (rfc822);
111                                 else
112                                         parameters.Remove ("modification-date");
113                         }
114                 }
115
116                 public string DispositionType {
117                         get { return dispositionType; }
118                         set {
119                                 if (value == null)
120                                         throw new ArgumentNullException ();
121                                 if (value.Length < 1)
122                                         throw new ArgumentException ();
123                                 dispositionType = value;
124                         }
125                 }
126
127                 public string FileName {
128                         get { return parameters["filename"]; }
129                         set { parameters["filename"] = value; }
130                 }
131
132                 public bool Inline {
133                         get { return String.Compare (dispositionType, DispositionTypeNames.Inline, true, CultureInfo.InvariantCulture) == 0; }
134                         set {
135                                 if (value)
136                                         dispositionType = DispositionTypeNames.Inline;
137                                 else
138                                         dispositionType = DispositionTypeNames.Attachment;
139                         }
140                 }
141
142                 public DateTime ModificationDate {
143                         get {
144                                 if (parameters.ContainsKey ("modification-date"))
145                                         return DateTime.ParseExact (parameters["modification-date"], rfc822, null);
146                                 else
147                                         return DateTime.MinValue;
148                         }
149                         set {
150                                 if (value > DateTime.MinValue)
151                                         parameters["modification-date"] = value.ToString (rfc822);
152                                 else
153                                         parameters.Remove ("modification-date");
154                         }
155                 }
156
157                 public StringDictionary Parameters {
158                         get { return parameters; }
159                 }
160
161                 public DateTime ReadDate {
162                         get {
163                                 if (parameters.ContainsKey ("read-date"))
164                                         return DateTime.ParseExact (parameters["read-date"], rfc822, null);
165                                 else
166                                         return DateTime.MinValue;
167                         }
168                         set {
169                                 if (value > DateTime.MinValue)
170                                         parameters["read-date"] = value.ToString (rfc822);
171                                 else
172                                         parameters.Remove ("read-date");
173                         }
174                 }
175
176                 public long Size {
177                         get {
178                                 if (parameters.ContainsKey ("size"))
179                                         return long.Parse (parameters["size"]);
180                                 else
181                                         return -1;
182                         }
183                         set {
184                                 if (value > -1)
185                                         parameters["size"] = value.ToString ();
186                                 else
187                                         parameters.Remove ("size");
188                         }
189                 }
190
191                 #endregion // Properties
192
193                 #region Methods
194
195                 public override bool Equals (object obj)
196                 {
197                         return Equals (obj as ContentDisposition);
198                 }
199
200                 bool Equals (ContentDisposition other)
201                 {
202                         return other != null && ToString () == other.ToString ();
203                 }
204
205                 public override int GetHashCode ()
206                 {
207                         return ToString ().GetHashCode ();
208                 }
209
210                 public override string ToString ()
211                 {
212                         // the content-disposition header as in RFC 2183
213                         // ex. attachment; filename=genome.jpeg; modification-date="Wed, 12 Feb 1997 16:29:51 -0500";
214                         // the dates must be quoted and in RFC 822 format
215                         //
216                         // According to RFC 2183, the filename field value follows the definition
217                         // given in RFC 1521, which is
218                         //
219                         //  value := token / quoted-string
220                         //
221                         StringBuilder sb = new StringBuilder ();
222                         sb.Append (DispositionType.ToLower ());
223                         if (Parameters != null && Parameters.Count > 0) {
224                                 bool quote = false;
225                                 string key, value;
226                                 
227                                 foreach (DictionaryEntry pair in Parameters)
228                                 {
229                                         if (pair.Value != null && pair.Value.ToString ().Length > 0) {
230                                                 sb.Append ("; ");
231                                                 sb.Append (pair.Key);
232                                                 sb.Append ("=");
233
234                                                 key = pair.Key.ToString ();
235                                                 value = pair.Value.ToString ();
236                                                 if ((key == "filename" && value.IndexOf (' ') != -1) || key.EndsWith ("date"))
237                                                         quote = true;
238                                                 else
239                                                         quote = false;
240                                                 
241                                                 if (quote)
242                                                         sb.Append ("\"");
243                                                 sb.Append (value);
244                                                 if (quote)
245                                                         sb.Append ("\"");
246                                         }
247                                 }
248                         }
249                         return sb.ToString ();
250                 }
251
252                 #endregion // Methods
253         }
254 }
255
256 #endif // NET_2_0