[System] Use 'ObjCRuntimeInternal' as the namespace instead of 'ObjCRuntime'. (#4820)
[mono.git] / mcs / class / System / System.Net / MacProxy.cs
1 // 
2 // MacProxy.cs
3 //  
4 // Author: Jeffrey Stedfast <jeff@xamarin.com>
5 // 
6 // Copyright (c) 2012-2014 Xamarin Inc.
7 // 
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
14 // 
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
17 // 
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 // THE SOFTWARE.
25 // 
26
27 using System;
28 using System.Net;
29 using System.Collections.Generic;
30 using System.Runtime.InteropServices;
31 using System.Threading;
32 using ObjCRuntimeInternal;
33
34 namespace Mono.Net
35 {
36         internal class CFType {
37                 [DllImport (CFObject.CoreFoundationLibrary, EntryPoint="CFGetTypeID")]
38                 public static extern IntPtr GetTypeID (IntPtr typeRef);
39         }
40
41         internal class CFObject : IDisposable, INativeObject
42         {
43                 public const string CoreFoundationLibrary = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
44                 const string SystemLibrary = "/usr/lib/libSystem.dylib";
45
46                 [DllImport (SystemLibrary)]
47                 public static extern IntPtr dlopen (string path, int mode);
48
49                 [DllImport (SystemLibrary)]
50                 static extern IntPtr dlsym (IntPtr handle, string symbol);
51
52                 [DllImport (SystemLibrary)]
53                 public static extern void dlclose (IntPtr handle);
54
55                 public static IntPtr GetIndirect (IntPtr handle, string symbol)
56                 {
57                         return dlsym (handle, symbol);
58                 }
59
60                 public static CFString GetStringConstant (IntPtr handle, string symbol)
61                 {
62                         var indirect = dlsym (handle, symbol);
63                         if (indirect == IntPtr.Zero)
64                                 return null;
65                         var actual = Marshal.ReadIntPtr (indirect);
66                         if (actual == IntPtr.Zero)
67                                 return null;
68                         return new CFString (actual, false);
69                 }
70
71                 public static IntPtr GetIntPtr (IntPtr handle, string symbol)
72                 {
73                         var indirect = dlsym (handle, symbol);
74                         if (indirect == IntPtr.Zero)
75                                 return IntPtr.Zero;
76                         return Marshal.ReadIntPtr (indirect);
77                 }
78
79                 public static IntPtr GetCFObjectHandle (IntPtr handle, string symbol)
80                 {
81                         var indirect = dlsym (handle, symbol);
82                         if (indirect == IntPtr.Zero)
83                                 return IntPtr.Zero;
84
85                         return Marshal.ReadIntPtr (indirect);
86                 }
87
88                 public CFObject (IntPtr handle, bool own)
89                 {
90                         Handle = handle;
91
92                         if (!own)
93                                 Retain ();
94                 }
95
96                 ~CFObject ()
97                 {
98                         Dispose (false);
99                 }
100
101                 public IntPtr Handle { get; private set; }
102
103                 [DllImport (CoreFoundationLibrary)]
104                 internal extern static IntPtr CFRetain (IntPtr handle);
105
106                 void Retain ()
107                 {
108                         CFRetain (Handle);
109                 }
110
111                 [DllImport (CoreFoundationLibrary)]
112                 internal extern static void CFRelease (IntPtr handle);
113
114                 void Release ()
115                 {
116                         CFRelease (Handle);
117                 }
118
119                 protected virtual void Dispose (bool disposing)
120                 {
121                         if (Handle != IntPtr.Zero) {
122                                 Release ();
123                                 Handle = IntPtr.Zero;
124                         }
125                 }
126
127                 public void Dispose ()
128                 {
129                         Dispose (true);
130                         GC.SuppressFinalize (this);
131                 }
132         }
133
134         internal class CFArray : CFObject
135         {
136                 public CFArray (IntPtr handle, bool own) : base (handle, own) { }
137
138                 [DllImport (CoreFoundationLibrary)]
139                 extern static IntPtr CFArrayCreate (IntPtr allocator, IntPtr values, /* CFIndex */ IntPtr numValues, IntPtr callbacks);
140                 static readonly IntPtr kCFTypeArrayCallbacks;
141
142                 static CFArray ()
143                 {
144                         var handle = dlopen (CoreFoundationLibrary, 0);
145                         if (handle == IntPtr.Zero)
146                                 return;
147
148                         try {
149                                 kCFTypeArrayCallbacks = GetIndirect (handle, "kCFTypeArrayCallBacks");
150                         } finally {
151                                 dlclose (handle);
152                         }
153                 }
154                 
155                 public static CFArray FromNativeObjects (params INativeObject[] values)
156                 {
157                         return new CFArray (Create (values), true);
158                 }
159
160                 public static unsafe IntPtr Create (params IntPtr[] values)
161                 {
162                         if (values == null)
163                                 throw new ArgumentNullException ("values");
164                         fixed (IntPtr* pv = values) {
165                                 return CFArrayCreate (IntPtr.Zero, (IntPtr) pv, (IntPtr)values.Length, kCFTypeArrayCallbacks);
166                         }
167                 }
168
169                 internal static unsafe CFArray CreateArray (params IntPtr[] values)
170                 {
171                         if (values == null)
172                                 throw new ArgumentNullException ("values");
173
174                         fixed (IntPtr *pv = values) {
175                                 IntPtr handle = CFArrayCreate (IntPtr.Zero, (IntPtr) pv, (IntPtr) values.Length, kCFTypeArrayCallbacks);
176
177                                 return new CFArray (handle, false);
178                         }
179                 }
180                 
181                 public static CFArray CreateArray (params INativeObject[] values)
182                 {
183                         return new CFArray (Create (values), true);
184                 }
185
186                 public static IntPtr Create (params INativeObject[] values)
187                 {
188                         if (values == null)
189                                 throw new ArgumentNullException ("values");
190                         IntPtr[] _values = new IntPtr [values.Length];
191                         for (int i = 0; i < _values.Length; ++i)
192                                 _values [i] = values [i].Handle;
193                         return Create (_values);
194                 }
195
196                 [DllImport (CoreFoundationLibrary)]
197                 extern static /* CFIndex */ IntPtr CFArrayGetCount (IntPtr handle);
198
199                 public int Count {
200                         get { return (int) CFArrayGetCount (Handle); }
201                 }
202
203                 [DllImport (CoreFoundationLibrary)]
204                 extern static IntPtr CFArrayGetValueAtIndex (IntPtr handle, /* CFIndex */ IntPtr index);
205
206                 public IntPtr this[int index] {
207                         get {
208                                 return CFArrayGetValueAtIndex (Handle, (IntPtr) index);
209                         }
210                 }
211                 
212                 static public T [] ArrayFromHandle<T> (IntPtr handle, Func<IntPtr, T> creation) where T : class, INativeObject
213                 {
214                         if (handle == IntPtr.Zero)
215                                 return null;
216
217                         var c = CFArrayGetCount (handle);
218                         T [] ret = new T [(int)c];
219
220                         for (uint i = 0; i < (uint)c; i++) {
221                                 ret [i] = creation (CFArrayGetValueAtIndex (handle, (IntPtr)i));
222                         }
223                         return ret;
224                 }
225         }
226
227         internal class CFNumber : CFObject
228         {
229                 public CFNumber (IntPtr handle, bool own) : base (handle, own) { }
230
231                 [DllImport (CoreFoundationLibrary)]
232                 [return: MarshalAs (UnmanagedType.I1)]
233                 extern static bool CFNumberGetValue (IntPtr handle, /* CFNumberType */ IntPtr type, [MarshalAs (UnmanagedType.I1)] out bool value);
234
235                 public static bool AsBool (IntPtr handle)
236                 {
237                         bool value;
238
239                         if (handle == IntPtr.Zero)
240                                 return false;
241
242                         CFNumberGetValue (handle, (IntPtr) 1, out value);
243
244                         return value;
245                 }
246
247                 public static implicit operator bool (CFNumber number)
248                 {
249                         return AsBool (number.Handle);
250                 }
251
252                 [DllImport (CoreFoundationLibrary)]
253                 [return: MarshalAs (UnmanagedType.I1)]
254                 extern static bool CFNumberGetValue (IntPtr handle, /* CFNumberType */ IntPtr type, out int value);
255
256                 public static int AsInt32 (IntPtr handle)
257                 {
258                         int value;
259
260                         if (handle == IntPtr.Zero)
261                                 return 0;
262
263                         // 9 == kCFNumberIntType == C int
264                         CFNumberGetValue (handle, (IntPtr) 9, out value);
265
266                         return value;
267                 }
268                 
269                 [DllImport (CoreFoundationLibrary)]
270                 extern static IntPtr CFNumberCreate (IntPtr allocator, IntPtr theType, IntPtr valuePtr);        
271
272                 public static CFNumber FromInt32 (int number)
273                 {
274                         // 9 == kCFNumberIntType == C int
275                         return new CFNumber (CFNumberCreate (IntPtr.Zero, (IntPtr)9, (IntPtr)number), true);
276                 }
277
278                 public static implicit operator int (CFNumber number)
279                 {
280                         return AsInt32 (number.Handle);
281                 }
282         }
283
284         internal struct CFRange {
285                 public IntPtr Location, Length;
286                 
287                 public CFRange (int loc, int len)
288                 {
289                         Location = (IntPtr) loc;
290                         Length = (IntPtr) len;
291                 }
292         }
293
294         internal struct CFStreamClientContext {
295                 public IntPtr Version;
296                 public IntPtr Info;
297                 public IntPtr Retain;
298                 public IntPtr Release;
299                 public IntPtr CopyDescription;
300         }
301
302         internal class CFString : CFObject
303         {
304                 string str;
305
306                 public CFString (IntPtr handle, bool own) : base (handle, own) { }
307
308                 [DllImport (CoreFoundationLibrary)]
309                 extern static IntPtr CFStringCreateWithCharacters (IntPtr alloc, IntPtr chars, /* CFIndex */ IntPtr length);
310
311                 public static CFString Create (string value)
312                 {
313                         IntPtr handle;
314
315                         unsafe {
316                                 fixed (char *ptr = value) {
317                                         handle = CFStringCreateWithCharacters (IntPtr.Zero, (IntPtr) ptr, (IntPtr) value.Length);
318                                 }
319                         }
320
321                         if (handle == IntPtr.Zero)
322                                 return null;
323
324                         return new CFString (handle, true);
325                 }
326
327                 [DllImport (CoreFoundationLibrary)]
328                 extern static /* CFIndex */ IntPtr CFStringGetLength (IntPtr handle);
329
330                 public int Length {
331                         get {
332                                 if (str != null)
333                                         return str.Length;
334
335                                 return (int) CFStringGetLength (Handle);
336                         }
337                 }
338
339                 [DllImport (CoreFoundationLibrary)]
340                 extern static IntPtr CFStringGetCharactersPtr (IntPtr handle);
341
342                 [DllImport (CoreFoundationLibrary)]
343                 extern static IntPtr CFStringGetCharacters (IntPtr handle, CFRange range, IntPtr buffer);
344
345                 public static string AsString (IntPtr handle)
346                 {
347                         if (handle == IntPtr.Zero)
348                                 return null;
349                         
350                         int len = (int) CFStringGetLength (handle);
351                         
352                         if (len == 0)
353                                 return string.Empty;
354                         
355                         IntPtr chars = CFStringGetCharactersPtr (handle);
356                         IntPtr buffer = IntPtr.Zero;
357                         
358                         if (chars == IntPtr.Zero) {
359                                 CFRange range = new CFRange (0, len);
360                                 buffer = Marshal.AllocHGlobal (len * 2);
361                                 CFStringGetCharacters (handle, range, buffer);
362                                 chars = buffer;
363                         }
364
365                         string str;
366
367                         unsafe {
368                                 str = new string ((char *) chars, 0, len);
369                         }
370                         
371                         if (buffer != IntPtr.Zero)
372                                 Marshal.FreeHGlobal (buffer);
373
374                         return str;
375                 }
376
377                 public override string ToString ()
378                 {
379                         if (str == null)
380                                 str = AsString (Handle);
381
382                         return str;
383                 }
384
385                 public static implicit operator string (CFString str)
386                 {
387                         return str.ToString ();
388                 }
389
390                 public static implicit operator CFString (string str)
391                 {
392                         return Create (str);
393                 }
394         }
395
396         
397         internal class CFData : CFObject
398         {
399                 public CFData (IntPtr handle, bool own) : base (handle, own) { }
400         
401                 [DllImport (CoreFoundationLibrary)]
402                 extern static /* CFDataRef */ IntPtr CFDataCreate (/* CFAllocatorRef */ IntPtr allocator, /* UInt8* */ IntPtr bytes, /* CFIndex */ IntPtr length);
403                 public unsafe static CFData FromData (byte [] buffer)
404                 {
405                         fixed (byte* p = buffer)
406                         {
407                                 return FromData ((IntPtr)p, (IntPtr)buffer.Length);
408                         }
409                 }
410
411                 public static CFData FromData (IntPtr buffer, IntPtr length)
412                 {
413                         return new CFData (CFDataCreate (IntPtr.Zero, buffer, length), true);
414                 }
415                 
416                 public IntPtr Length {
417                         get { return CFDataGetLength (Handle); }
418                 }
419
420                 [DllImport (CoreFoundationLibrary)]
421                 extern static /* CFIndex */ IntPtr CFDataGetLength (/* CFDataRef */ IntPtr theData);
422
423                 [DllImport (CoreFoundationLibrary)]
424                 extern static /* UInt8* */ IntPtr CFDataGetBytePtr (/* CFDataRef */ IntPtr theData);
425
426                 /*
427                  * Exposes a read-only pointer to the underlying storage.
428                  */
429                 public IntPtr Bytes {
430                         get { return CFDataGetBytePtr (Handle); }
431                 }
432
433                 public byte this [long idx] {
434                         get {
435                                 if (idx < 0 || (ulong) idx > (ulong) Length)
436                                         throw new ArgumentException ("idx");
437                                 return Marshal.ReadByte (new IntPtr (Bytes.ToInt64 () + idx));
438                         }
439
440                         set {
441                                 throw new NotImplementedException ("NSData arrays can not be modified, use an NSMutableData instead");
442                         }
443                 }
444
445         }
446
447         internal class CFDictionary : CFObject
448         {
449                 static readonly IntPtr KeyCallbacks;
450                 static readonly IntPtr ValueCallbacks;
451                 
452                 static CFDictionary ()
453                 {
454                         var handle = dlopen (CoreFoundationLibrary, 0);
455                         if (handle == IntPtr.Zero)
456                                 return;
457
458                         try {           
459                                 KeyCallbacks = GetIndirect (handle, "kCFTypeDictionaryKeyCallBacks");
460                                 ValueCallbacks = GetIndirect (handle, "kCFTypeDictionaryValueCallBacks");
461                         } finally {
462                                 dlclose (handle);
463                         }
464                 }
465
466                 public CFDictionary (IntPtr handle, bool own) : base (handle, own) { }
467
468                 public static CFDictionary FromObjectAndKey (IntPtr obj, IntPtr key)
469                 {
470                         return new CFDictionary (CFDictionaryCreate (IntPtr.Zero, new IntPtr[] { key }, new IntPtr [] { obj }, (IntPtr)1, KeyCallbacks, ValueCallbacks), true);
471                 }
472
473                 public static CFDictionary FromKeysAndObjects (IList<Tuple<IntPtr,IntPtr>> items)
474                 {
475                         var keys = new IntPtr [items.Count];
476                         var values = new IntPtr [items.Count];
477                         for (int i = 0; i < items.Count; i++) {
478                                 keys [i] = items [i].Item1;
479                                 values [i] = items [i].Item2;
480                         }
481                         return new CFDictionary (CFDictionaryCreate (IntPtr.Zero, keys, values, (IntPtr)items.Count, KeyCallbacks, ValueCallbacks), true);
482                 }
483
484                 [DllImport (CoreFoundationLibrary)]
485                 extern static IntPtr CFDictionaryCreate (IntPtr allocator, IntPtr[] keys, IntPtr[] vals, IntPtr len, IntPtr keyCallbacks, IntPtr valCallbacks);
486
487                 [DllImport (CoreFoundationLibrary)]
488                 extern static IntPtr CFDictionaryGetValue (IntPtr handle, IntPtr key);
489
490                 [DllImport (CoreFoundationLibrary)]
491                 extern static IntPtr CFDictionaryCreateCopy (IntPtr allocator, IntPtr handle);
492
493                 public CFDictionary Copy ()
494                 {
495                         return new CFDictionary (CFDictionaryCreateCopy (IntPtr.Zero, Handle), true);
496                 }
497                 
498                 public CFMutableDictionary MutableCopy ()
499                 {
500                         return new CFMutableDictionary (CFDictionaryCreateMutableCopy (IntPtr.Zero, IntPtr.Zero, Handle), true);
501                 }
502
503                 [DllImport (CoreFoundationLibrary)]
504                 extern static IntPtr CFDictionaryCreateMutableCopy (IntPtr allocator, IntPtr capacity, IntPtr theDict);
505
506                 public IntPtr GetValue (IntPtr key)
507                 {
508                         return CFDictionaryGetValue (Handle, key);
509                 }
510
511                 public IntPtr this[IntPtr key] {
512                         get {
513                                 return GetValue (key);
514                         }
515                 }
516         }
517         
518         internal class CFMutableDictionary : CFDictionary
519         {
520                 public CFMutableDictionary (IntPtr handle, bool own) : base (handle, own) { }
521
522                 public void SetValue (IntPtr key, IntPtr val)
523                 {
524                         CFDictionarySetValue (Handle, key, val);
525                 }
526
527                 public static CFMutableDictionary Create ()
528                 {
529                         var handle = CFDictionaryCreateMutable (IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
530                         if (handle == IntPtr.Zero)
531                                 throw new InvalidOperationException ();
532                         return new CFMutableDictionary (handle, true);
533                 }
534
535                 [DllImport (CoreFoundationLibrary)]
536                 extern static void CFDictionarySetValue (IntPtr handle, IntPtr key, IntPtr val);
537
538                 [DllImport (CoreFoundationLibrary)]
539                 extern static IntPtr CFDictionaryCreateMutable (IntPtr allocator, IntPtr capacity, IntPtr keyCallback, IntPtr valueCallbacks);
540
541         }
542
543         internal class CFUrl : CFObject
544         {
545                 public CFUrl (IntPtr handle, bool own) : base (handle, own) { }
546
547                 [DllImport (CoreFoundationLibrary)]
548                 extern static IntPtr CFURLCreateWithString (IntPtr allocator, IntPtr str, IntPtr baseURL);
549
550                 public static CFUrl Create (string absolute)
551                 {
552                         if (string.IsNullOrEmpty (absolute))
553                                 return null;
554
555                         CFString str = CFString.Create (absolute);
556                         IntPtr handle = CFURLCreateWithString (IntPtr.Zero, str.Handle, IntPtr.Zero);
557                         str.Dispose ();
558
559                         if (handle == IntPtr.Zero)
560                                 return null;
561
562                         return new CFUrl (handle, true);
563                 }
564         }
565
566         internal class CFRunLoop : CFObject
567         {
568                 [DllImport (CFObject.CoreFoundationLibrary)]
569                 static extern void CFRunLoopAddSource (IntPtr rl, IntPtr source, IntPtr mode);
570
571                 [DllImport (CFObject.CoreFoundationLibrary)]
572                 static extern void CFRunLoopRemoveSource (IntPtr rl, IntPtr source, IntPtr mode);
573
574                 [DllImport (CFObject.CoreFoundationLibrary)]
575                 static extern int CFRunLoopRunInMode (IntPtr mode, double seconds, bool returnAfterSourceHandled);
576
577                 [DllImport (CFObject.CoreFoundationLibrary)]
578                 static extern IntPtr CFRunLoopGetCurrent ();
579
580                 [DllImport (CFObject.CoreFoundationLibrary)]
581                 static extern void CFRunLoopStop (IntPtr rl);
582
583                 public CFRunLoop (IntPtr handle, bool own): base (handle, own)
584                 {
585                 }
586
587                 public static CFRunLoop CurrentRunLoop {
588                         get { return new CFRunLoop (CFRunLoopGetCurrent (), false); }
589                 }
590
591                 public void AddSource (IntPtr source, CFString mode)
592                 {
593                         CFRunLoopAddSource (Handle, source, mode.Handle);
594                 }
595
596                 public void RemoveSource (IntPtr source, CFString mode)
597                 {
598                         CFRunLoopRemoveSource (Handle, source, mode.Handle);
599                 }
600
601                 public int RunInMode (CFString mode, double seconds, bool returnAfterSourceHandled)
602                 {
603                         return CFRunLoopRunInMode (mode.Handle, seconds, returnAfterSourceHandled);
604                 }
605
606                 public void Stop ()
607                 {
608                         CFRunLoopStop (Handle);
609                 }
610         }
611
612         internal enum CFProxyType {
613                 None,
614                 AutoConfigurationUrl,
615                 AutoConfigurationJavaScript,
616                 FTP,
617                 HTTP,
618                 HTTPS,
619                 SOCKS
620         }
621         
622         internal class CFProxy {
623                 //static IntPtr kCFProxyAutoConfigurationHTTPResponseKey;
624                 static IntPtr kCFProxyAutoConfigurationJavaScriptKey;
625                 static IntPtr kCFProxyAutoConfigurationURLKey;
626                 static IntPtr kCFProxyHostNameKey;
627                 static IntPtr kCFProxyPasswordKey;
628                 static IntPtr kCFProxyPortNumberKey;
629                 static IntPtr kCFProxyTypeKey;
630                 static IntPtr kCFProxyUsernameKey;
631
632                 //static IntPtr kCFProxyTypeNone;
633                 static IntPtr kCFProxyTypeAutoConfigurationURL;
634                 static IntPtr kCFProxyTypeAutoConfigurationJavaScript;
635                 static IntPtr kCFProxyTypeFTP;
636                 static IntPtr kCFProxyTypeHTTP;
637                 static IntPtr kCFProxyTypeHTTPS;
638                 static IntPtr kCFProxyTypeSOCKS;
639
640                 static CFProxy ()
641                 {
642                         IntPtr handle = CFObject.dlopen (CFNetwork.CFNetworkLibrary, 0);
643
644                         //kCFProxyAutoConfigurationHTTPResponseKey = CFObject.GetCFObjectHandle (handle, "kCFProxyAutoConfigurationHTTPResponseKey");
645                         kCFProxyAutoConfigurationJavaScriptKey = CFObject.GetCFObjectHandle (handle, "kCFProxyAutoConfigurationJavaScriptKey");
646                         kCFProxyAutoConfigurationURLKey = CFObject.GetCFObjectHandle (handle, "kCFProxyAutoConfigurationURLKey");
647                         kCFProxyHostNameKey = CFObject.GetCFObjectHandle (handle, "kCFProxyHostNameKey");
648                         kCFProxyPasswordKey = CFObject.GetCFObjectHandle (handle, "kCFProxyPasswordKey");
649                         kCFProxyPortNumberKey = CFObject.GetCFObjectHandle (handle, "kCFProxyPortNumberKey");
650                         kCFProxyTypeKey = CFObject.GetCFObjectHandle (handle, "kCFProxyTypeKey");
651                         kCFProxyUsernameKey = CFObject.GetCFObjectHandle (handle, "kCFProxyUsernameKey");
652
653                         //kCFProxyTypeNone = CFObject.GetCFObjectHandle (handle, "kCFProxyTypeNone");
654                         kCFProxyTypeAutoConfigurationURL = CFObject.GetCFObjectHandle (handle, "kCFProxyTypeAutoConfigurationURL");
655                         kCFProxyTypeAutoConfigurationJavaScript = CFObject.GetCFObjectHandle (handle, "kCFProxyTypeAutoConfigurationJavaScript");
656                         kCFProxyTypeFTP = CFObject.GetCFObjectHandle (handle, "kCFProxyTypeFTP");
657                         kCFProxyTypeHTTP = CFObject.GetCFObjectHandle (handle, "kCFProxyTypeHTTP");
658                         kCFProxyTypeHTTPS = CFObject.GetCFObjectHandle (handle, "kCFProxyTypeHTTPS");
659                         kCFProxyTypeSOCKS = CFObject.GetCFObjectHandle (handle, "kCFProxyTypeSOCKS");
660
661                         CFObject.dlclose (handle);
662                 }
663
664                 CFDictionary settings;
665                 
666                 internal CFProxy (CFDictionary settings)
667                 {
668                         this.settings = settings;
669                 }
670                 
671                 static CFProxyType CFProxyTypeToEnum (IntPtr type)
672                 {
673                         if (type == kCFProxyTypeAutoConfigurationJavaScript)
674                                 return CFProxyType.AutoConfigurationJavaScript;
675
676                         if (type == kCFProxyTypeAutoConfigurationURL)
677                                 return CFProxyType.AutoConfigurationUrl;
678
679                         if (type == kCFProxyTypeFTP)
680                                 return CFProxyType.FTP;
681
682                         if (type == kCFProxyTypeHTTP)
683                                 return CFProxyType.HTTP;
684
685                         if (type == kCFProxyTypeHTTPS)
686                                 return CFProxyType.HTTPS;
687
688                         if (type == kCFProxyTypeSOCKS)
689                                 return CFProxyType.SOCKS;
690                         
691                         return CFProxyType.None;
692                 }
693                 
694 #if false
695                 // AFAICT these get used with CFNetworkExecuteProxyAutoConfiguration*()
696                 
697                 // TODO: bind CFHTTPMessage so we can return the proper type here.
698                 public IntPtr AutoConfigurationHTTPResponse {
699                         get { return settings[kCFProxyAutoConfigurationHTTPResponseKey]; }
700                 }
701 #endif
702
703                 public IntPtr AutoConfigurationJavaScript {
704                         get {
705                                 if (kCFProxyAutoConfigurationJavaScriptKey == IntPtr.Zero)
706                                         return IntPtr.Zero;
707                                 
708                                 return settings[kCFProxyAutoConfigurationJavaScriptKey];
709                         }
710                 }
711                 
712                 public IntPtr AutoConfigurationUrl {
713                         get {
714                                 if (kCFProxyAutoConfigurationURLKey == IntPtr.Zero)
715                                         return IntPtr.Zero;
716                                 
717                                 return settings[kCFProxyAutoConfigurationURLKey];
718                         }
719                 }
720                 
721                 public string HostName {
722                         get {
723                                 if (kCFProxyHostNameKey == IntPtr.Zero)
724                                         return null;
725                                 
726                                 return CFString.AsString (settings[kCFProxyHostNameKey]);
727                         }
728                 }
729                 
730                 public string Password {
731                         get {
732                                 if (kCFProxyPasswordKey == IntPtr.Zero)
733                                         return null;
734
735                                 return CFString.AsString (settings[kCFProxyPasswordKey]);
736                         }
737                 }
738                 
739                 public int Port {
740                         get {
741                                 if (kCFProxyPortNumberKey == IntPtr.Zero)
742                                         return 0;
743                                 
744                                 return CFNumber.AsInt32 (settings[kCFProxyPortNumberKey]);
745                         }
746                 }
747                 
748                 public CFProxyType ProxyType {
749                         get {
750                                 if (kCFProxyTypeKey == IntPtr.Zero)
751                                         return CFProxyType.None;
752                                 
753                                 return CFProxyTypeToEnum (settings[kCFProxyTypeKey]);
754                         }
755                 }
756                 
757                 public string Username {
758                         get {
759                                 if (kCFProxyUsernameKey == IntPtr.Zero)
760                                         return null;
761
762                                 return CFString.AsString (settings[kCFProxyUsernameKey]);
763                         }
764                 }
765         }
766         
767         internal class CFProxySettings {
768                 static IntPtr kCFNetworkProxiesHTTPEnable;
769                 static IntPtr kCFNetworkProxiesHTTPPort;
770                 static IntPtr kCFNetworkProxiesHTTPProxy;
771                 static IntPtr kCFNetworkProxiesProxyAutoConfigEnable;
772                 static IntPtr kCFNetworkProxiesProxyAutoConfigJavaScript;
773                 static IntPtr kCFNetworkProxiesProxyAutoConfigURLString;
774
775                 static CFProxySettings ()
776                 {
777                         IntPtr handle = CFObject.dlopen (CFNetwork.CFNetworkLibrary, 0);
778
779                         kCFNetworkProxiesHTTPEnable = CFObject.GetCFObjectHandle (handle, "kCFNetworkProxiesHTTPEnable");
780                         kCFNetworkProxiesHTTPPort = CFObject.GetCFObjectHandle (handle, "kCFNetworkProxiesHTTPPort");
781                         kCFNetworkProxiesHTTPProxy = CFObject.GetCFObjectHandle (handle, "kCFNetworkProxiesHTTPProxy");
782                         kCFNetworkProxiesProxyAutoConfigEnable = CFObject.GetCFObjectHandle (handle, "kCFNetworkProxiesProxyAutoConfigEnable");
783                         kCFNetworkProxiesProxyAutoConfigJavaScript = CFObject.GetCFObjectHandle (handle, "kCFNetworkProxiesProxyAutoConfigJavaScript");
784                         kCFNetworkProxiesProxyAutoConfigURLString = CFObject.GetCFObjectHandle (handle, "kCFNetworkProxiesProxyAutoConfigURLString");
785
786                         CFObject.dlclose (handle);
787                 }
788
789                 CFDictionary settings;
790                 
791                 public CFProxySettings (CFDictionary settings)
792                 {
793                         this.settings = settings;
794                 }
795                 
796                 public CFDictionary Dictionary {
797                         get { return settings; }
798                 }
799                 
800                 public bool HTTPEnable {
801                         get {
802                                 if (kCFNetworkProxiesHTTPEnable == IntPtr.Zero)
803                                         return false;
804
805                                 return CFNumber.AsBool (settings[kCFNetworkProxiesHTTPEnable]);
806                         }
807                 }
808                 
809                 public int HTTPPort {
810                         get {
811                                 if (kCFNetworkProxiesHTTPPort == IntPtr.Zero)
812                                         return 0;
813                                 
814                                 return CFNumber.AsInt32 (settings[kCFNetworkProxiesHTTPPort]);
815                         }
816                 }
817                 
818                 public string HTTPProxy {
819                         get {
820                                 if (kCFNetworkProxiesHTTPProxy == IntPtr.Zero)
821                                         return null;
822                                 
823                                 return CFString.AsString (settings[kCFNetworkProxiesHTTPProxy]);
824                         }
825                 }
826                 
827                 public bool ProxyAutoConfigEnable {
828                         get {
829                                 if (kCFNetworkProxiesProxyAutoConfigEnable == IntPtr.Zero)
830                                         return false;
831                                 
832                                 return CFNumber.AsBool (settings[kCFNetworkProxiesProxyAutoConfigEnable]);
833                         }
834                 }
835                 
836                 public string ProxyAutoConfigJavaScript {
837                         get {
838                                 if (kCFNetworkProxiesProxyAutoConfigJavaScript == IntPtr.Zero)
839                                         return null;
840                                 
841                                 return CFString.AsString (settings[kCFNetworkProxiesProxyAutoConfigJavaScript]);
842                         }
843                 }
844                 
845                 public string ProxyAutoConfigURLString {
846                         get {
847                                 if (kCFNetworkProxiesProxyAutoConfigURLString == IntPtr.Zero)
848                                         return null;
849                                 
850                                 return CFString.AsString (settings[kCFNetworkProxiesProxyAutoConfigURLString]);
851                         }
852                 }
853         }
854         
855         internal static class CFNetwork {
856 #if !MONOTOUCH
857                 public const string CFNetworkLibrary = "/System/Library/Frameworks/CoreServices.framework/Frameworks/CFNetwork.framework/CFNetwork";
858 #else
859                 public const string CFNetworkLibrary = "/System/Library/Frameworks/CFNetwork.framework/CFNetwork";
860 #endif
861                 
862                 [DllImport (CFNetworkLibrary, EntryPoint = "CFNetworkCopyProxiesForAutoConfigurationScript")]
863                 // CFArrayRef CFNetworkCopyProxiesForAutoConfigurationScript (CFStringRef proxyAutoConfigurationScript, CFURLRef targetURL, CFErrorRef* error);
864                 extern static IntPtr CFNetworkCopyProxiesForAutoConfigurationScriptSequential (IntPtr proxyAutoConfigurationScript, IntPtr targetURL, out IntPtr error);
865
866                 [DllImport (CFNetworkLibrary)]
867                 extern static IntPtr CFNetworkExecuteProxyAutoConfigurationURL (IntPtr proxyAutoConfigURL, IntPtr targetURL, CFProxyAutoConfigurationResultCallback cb, ref CFStreamClientContext clientContext);
868
869
870                 class GetProxyData : IDisposable {
871                         public IntPtr script;
872                         public IntPtr targetUri;
873                         public IntPtr error;
874                         public IntPtr result;
875                         public ManualResetEvent evt = new ManualResetEvent (false);
876
877                         public void Dispose ()
878                         {
879                                 evt.Close ();
880                         }
881                 }
882
883                 static object lock_obj = new object ();
884                 static Queue<GetProxyData> get_proxy_queue;
885                 static AutoResetEvent proxy_event;
886
887                 static void CFNetworkCopyProxiesForAutoConfigurationScriptThread ()
888                 {
889                         GetProxyData data;
890                         var data_left = true;
891
892                         while (true) {
893                                 proxy_event.WaitOne ();
894
895                                 do {
896                                         lock (lock_obj) {
897                                                 if (get_proxy_queue.Count == 0)
898                                                         break;
899                                                 data = get_proxy_queue.Dequeue ();
900                                                 data_left = get_proxy_queue.Count > 0;
901                                         }
902
903                                         data.result = CFNetworkCopyProxiesForAutoConfigurationScriptSequential (data.script, data.targetUri, out data.error);
904                                         data.evt.Set ();
905                                 } while (data_left);
906                         }
907                 }
908
909                 static IntPtr CFNetworkCopyProxiesForAutoConfigurationScript (IntPtr proxyAutoConfigurationScript, IntPtr targetURL, out IntPtr error)
910                 {
911                         // This method must only be called on only one thread during an application's life time.
912                         // Note that it's not enough to use a lock to make calls sequential across different threads,
913                         // it has to be one thread. Also note that that thread can't be the main thread, because the
914                         // main thread might be blocking waiting for this network request to finish.
915                         // Another possibility would be to use JavaScriptCore to execute this piece of
916                         // javascript ourselves, but unfortunately it's not available before iOS7.
917                         // See bug #7923 comment #21+.
918
919                         using (var data = new GetProxyData ()) {
920                                 data.script = proxyAutoConfigurationScript;
921                                 data.targetUri = targetURL;
922
923                                 lock (lock_obj) {
924                                         if (get_proxy_queue == null) {
925                                                 get_proxy_queue = new Queue<GetProxyData> ();
926                                                 proxy_event = new AutoResetEvent (false);
927                                                 new Thread (CFNetworkCopyProxiesForAutoConfigurationScriptThread) {
928                                                         IsBackground = true,
929                                                 }.Start ();
930                                         }
931                                         get_proxy_queue.Enqueue (data);
932                                         proxy_event.Set ();
933                                 }
934
935                                 data.evt.WaitOne ();
936
937                                 error = data.error;
938
939                                 return data.result;
940                         }
941                 }
942
943                 static CFArray CopyProxiesForAutoConfigurationScript (IntPtr proxyAutoConfigurationScript, CFUrl targetURL)
944                 {
945                         IntPtr err = IntPtr.Zero;
946                         IntPtr native = CFNetworkCopyProxiesForAutoConfigurationScript (proxyAutoConfigurationScript, targetURL.Handle, out err);
947                         
948                         if (native == IntPtr.Zero)
949                                 return null;
950                         
951                         return new CFArray (native, true);
952                 }
953                 
954                 public static CFProxy[] GetProxiesForAutoConfigurationScript (IntPtr proxyAutoConfigurationScript, CFUrl targetURL)
955                 {
956                         if (proxyAutoConfigurationScript == IntPtr.Zero)
957                                 throw new ArgumentNullException ("proxyAutoConfigurationScript");
958                         
959                         if (targetURL == null)
960                                 throw new ArgumentNullException ("targetURL");
961                         
962                         CFArray array = CopyProxiesForAutoConfigurationScript (proxyAutoConfigurationScript, targetURL);
963                         
964                         if (array == null)
965                                 return null;
966                         
967                         CFProxy[] proxies = new CFProxy [array.Count];
968                         for (int i = 0; i < proxies.Length; i++) {
969                                 CFDictionary dict = new CFDictionary (array[i], false);
970                                 proxies[i] = new CFProxy (dict);
971                         }
972
973                         array.Dispose ();
974                         
975                         return proxies;
976                 }
977                 
978                 public static CFProxy[] GetProxiesForAutoConfigurationScript (IntPtr proxyAutoConfigurationScript, Uri targetUri)
979                 {
980                         if (proxyAutoConfigurationScript == IntPtr.Zero)
981                                 throw new ArgumentNullException ("proxyAutoConfigurationScript");
982                         
983                         if (targetUri == null)
984                                 throw new ArgumentNullException ("targetUri");
985                         
986                         CFUrl targetURL = CFUrl.Create (targetUri.AbsoluteUri);
987                         CFProxy[] proxies = GetProxiesForAutoConfigurationScript (proxyAutoConfigurationScript, targetURL);
988                         targetURL.Dispose ();
989                         
990                         return proxies;
991                 }
992
993                 delegate void CFProxyAutoConfigurationResultCallback (IntPtr client, IntPtr proxyList, IntPtr error);
994
995                 public static CFProxy[] ExecuteProxyAutoConfigurationURL (IntPtr proxyAutoConfigURL, Uri targetURL)
996                 {
997                         CFUrl url = CFUrl.Create (targetURL.AbsoluteUri);
998                         if (url == null)
999                                 return null;
1000
1001                         CFProxy[] proxies = null;
1002
1003                         var runLoop = CFRunLoop.CurrentRunLoop;
1004
1005                         // Callback that will be called after executing the configuration script
1006                         CFProxyAutoConfigurationResultCallback cb = delegate (IntPtr client, IntPtr proxyList, IntPtr error) {
1007                                 if (proxyList != IntPtr.Zero) {
1008                                         var array = new CFArray (proxyList, false);
1009                                         proxies = new CFProxy [array.Count];
1010                                         for (int i = 0; i < proxies.Length; i++) {
1011                                                 CFDictionary dict = new CFDictionary (array[i], false);
1012                                                 proxies[i] = new CFProxy (dict);
1013                                         }
1014                                         array.Dispose ();
1015                                 }
1016                                 runLoop.Stop ();
1017                         };
1018
1019                         var clientContext = new CFStreamClientContext ();
1020                         var loopSource = CFNetworkExecuteProxyAutoConfigurationURL (proxyAutoConfigURL, url.Handle, cb, ref clientContext);
1021
1022                         // Create a private mode
1023                         var mode = CFString.Create ("Mono.MacProxy");
1024
1025                         runLoop.AddSource (loopSource, mode);
1026                         runLoop.RunInMode (mode, double.MaxValue, false);
1027                         runLoop.RemoveSource (loopSource, mode);
1028
1029                         return proxies;
1030                 }
1031                 
1032                 [DllImport (CFNetworkLibrary)]
1033                 // CFArrayRef CFNetworkCopyProxiesForURL (CFURLRef url, CFDictionaryRef proxySettings);
1034                 extern static IntPtr CFNetworkCopyProxiesForURL (IntPtr url, IntPtr proxySettings);
1035                 
1036                 static CFArray CopyProxiesForURL (CFUrl url, CFDictionary proxySettings)
1037                 {
1038                         IntPtr native = CFNetworkCopyProxiesForURL (url.Handle, proxySettings != null ? proxySettings.Handle : IntPtr.Zero);
1039                         
1040                         if (native == IntPtr.Zero)
1041                                 return null;
1042                         
1043                         return new CFArray (native, true);
1044                 }
1045                 
1046                 public static CFProxy[] GetProxiesForURL (CFUrl url, CFProxySettings proxySettings)
1047                 {
1048                         if (url == null || url.Handle == IntPtr.Zero)
1049                                 throw new ArgumentNullException ("url");
1050                         
1051                         if (proxySettings == null)
1052                                 proxySettings = GetSystemProxySettings ();
1053                         
1054                         CFArray array = CopyProxiesForURL (url, proxySettings.Dictionary);
1055                         
1056                         if (array == null)
1057                                 return null;
1058
1059                         CFProxy[] proxies = new CFProxy [array.Count];
1060                         for (int i = 0; i < proxies.Length; i++) {
1061                                 CFDictionary dict = new CFDictionary (array[i], false);
1062                                 proxies[i] = new CFProxy (dict);
1063                         }
1064
1065                         array.Dispose ();
1066                         
1067                         return proxies;
1068                 }
1069                 
1070                 public static CFProxy[] GetProxiesForUri (Uri uri, CFProxySettings proxySettings)
1071                 {
1072                         if (uri == null)
1073                                 throw new ArgumentNullException ("uri");
1074                         
1075                         CFUrl url = CFUrl.Create (uri.AbsoluteUri);
1076                         if (url == null)
1077                                 return null;
1078                         
1079                         CFProxy[] proxies = GetProxiesForURL (url, proxySettings);
1080                         url.Dispose ();
1081                         
1082                         return proxies;
1083                 }
1084                 
1085                 [DllImport (CFNetworkLibrary)]
1086                 // CFDictionaryRef CFNetworkCopySystemProxySettings (void);
1087                 extern static IntPtr CFNetworkCopySystemProxySettings ();
1088                 
1089                 public static CFProxySettings GetSystemProxySettings ()
1090                 {
1091                         IntPtr native = CFNetworkCopySystemProxySettings ();
1092                         
1093                         if (native == IntPtr.Zero)
1094                                 return null;
1095                         
1096                         var dict = new CFDictionary (native, true);
1097
1098                         return new CFProxySettings (dict);
1099                 }
1100                 
1101                 class CFWebProxy : IWebProxy {
1102                         ICredentials credentials;
1103                         bool userSpecified;
1104                         
1105                         public CFWebProxy ()
1106                         {
1107                         }
1108                         
1109                         public ICredentials Credentials {
1110                                 get { return credentials; }
1111                                 set {
1112                                         userSpecified = true;
1113                                         credentials = value;
1114                                 }
1115                         }
1116                         
1117                         static Uri GetProxyUri (CFProxy proxy, out NetworkCredential credentials)
1118                         {
1119                                 string protocol;
1120                                 
1121                                 switch (proxy.ProxyType) {
1122                                 case CFProxyType.FTP:
1123                                         protocol = "ftp://";
1124                                         break;
1125                                 case CFProxyType.HTTP:
1126                                 case CFProxyType.HTTPS:
1127                                         protocol = "http://";
1128                                         break;
1129                                 default:
1130                                         credentials = null;
1131                                         return null;
1132                                 }
1133                                 
1134                                 string username = proxy.Username;
1135                                 string password = proxy.Password;
1136                                 string hostname = proxy.HostName;
1137                                 int port = proxy.Port;
1138                                 string uri;
1139                                 
1140                                 if (username != null)
1141                                         credentials = new NetworkCredential (username, password);
1142                                 else
1143                                         credentials = null;
1144                                 
1145                                 uri = protocol + hostname + (port != 0 ? ':' + port.ToString () : string.Empty);
1146                                 
1147                                 return new Uri (uri, UriKind.Absolute);
1148                         }
1149                         
1150                         static Uri GetProxyUriFromScript (IntPtr script, Uri targetUri, out NetworkCredential credentials)
1151                         {
1152                                 CFProxy[] proxies = CFNetwork.GetProxiesForAutoConfigurationScript (script, targetUri);
1153                                 return SelectProxy (proxies, targetUri, out credentials);
1154                         }
1155
1156                         static Uri ExecuteProxyAutoConfigurationURL (IntPtr proxyAutoConfigURL, Uri targetUri, out NetworkCredential credentials)
1157                         {
1158                                 CFProxy[] proxies = CFNetwork.ExecuteProxyAutoConfigurationURL (proxyAutoConfigURL, targetUri);
1159                                 return SelectProxy (proxies, targetUri, out credentials);
1160                         }
1161
1162
1163                         static Uri SelectProxy (CFProxy[] proxies, Uri targetUri, out NetworkCredential credentials)
1164                         {
1165                                 if (proxies == null) {
1166                                         credentials = null;
1167                                         return targetUri;
1168                                 }
1169                                 
1170                                 for (int i = 0; i < proxies.Length; i++) {
1171                                         switch (proxies[i].ProxyType) {
1172                                         case CFProxyType.HTTPS:
1173                                         case CFProxyType.HTTP:
1174                                         case CFProxyType.FTP:
1175                                                 // create a Uri based on the hostname/port/etc info
1176                                                 return GetProxyUri (proxies[i], out credentials);
1177                                         case CFProxyType.SOCKS:
1178                                         default:
1179                                                 // unsupported proxy type, try the next one
1180                                                 break;
1181                                         case CFProxyType.None:
1182                                                 // no proxy should be used
1183                                                 credentials = null;
1184                                                 return targetUri;
1185                                         }
1186                                 }
1187                                 
1188                                 credentials = null;
1189                                 
1190                                 return null;
1191                         }
1192                         
1193                         public Uri GetProxy (Uri targetUri)
1194                         {
1195                                 NetworkCredential credentials = null;
1196                                 Uri proxy = null;
1197                                 
1198                                 if (targetUri == null)
1199                                         throw new ArgumentNullException ("targetUri");
1200                                 
1201                                 try {
1202                                         CFProxySettings settings = CFNetwork.GetSystemProxySettings ();
1203                                         CFProxy[] proxies = CFNetwork.GetProxiesForUri (targetUri, settings);
1204                                         
1205                                         if (proxies != null) {
1206                                                 for (int i = 0; i < proxies.Length && proxy == null; i++) {
1207                                                         switch (proxies[i].ProxyType) {
1208                                                         case CFProxyType.AutoConfigurationJavaScript:
1209                                                                 proxy = GetProxyUriFromScript (proxies[i].AutoConfigurationJavaScript, targetUri, out credentials);
1210                                                                 break;
1211                                                         case CFProxyType.AutoConfigurationUrl:
1212                                                                 proxy = ExecuteProxyAutoConfigurationURL (proxies[i].AutoConfigurationUrl, targetUri, out credentials);
1213                                                                 break;
1214                                                         case CFProxyType.HTTPS:
1215                                                         case CFProxyType.HTTP:
1216                                                         case CFProxyType.FTP:
1217                                                                 // create a Uri based on the hostname/port/etc info
1218                                                                 proxy = GetProxyUri (proxies[i], out credentials);
1219                                                                 break;
1220                                                         case CFProxyType.SOCKS:
1221                                                                 // unsupported proxy type, try the next one
1222                                                                 break;
1223                                                         case CFProxyType.None:
1224                                                                 // no proxy should be used
1225                                                                 proxy = targetUri;
1226                                                                 break;
1227                                                         }
1228                                                 }
1229                                                 
1230                                                 if (proxy == null) {
1231                                                         // no supported proxies for this Uri, fall back to trying to connect to targetUri directly
1232                                                         proxy = targetUri;
1233                                                 }
1234                                         } else {
1235                                                 proxy = targetUri;
1236                                         }
1237                                 } catch {
1238                                         // ignore errors while retrieving proxy data
1239                                         proxy = targetUri;
1240                                 }
1241                                 
1242                                 if (!userSpecified)
1243                                         this.credentials = credentials;
1244                                 
1245                                 return proxy;
1246                         }
1247                         
1248                         public bool IsBypassed (Uri targetUri)
1249                         {
1250                                 if (targetUri == null)
1251                                         throw new ArgumentNullException ("targetUri");
1252                                 
1253                                 return GetProxy (targetUri) == targetUri;
1254                         }
1255                 }
1256                 
1257                 public static IWebProxy GetDefaultProxy ()
1258                 {
1259                         return new CFWebProxy ();
1260                 }
1261         }
1262
1263         class CFBoolean : INativeObject, IDisposable {
1264                 IntPtr handle;
1265
1266                 public static readonly CFBoolean True;
1267                 public static readonly CFBoolean False;
1268
1269                 static CFBoolean ()
1270                 {
1271                         var handle = CFObject.dlopen (CFObject.CoreFoundationLibrary, 0);
1272                         if (handle == IntPtr.Zero)
1273                                 return;
1274                         try {
1275                                 True  = new CFBoolean (CFObject.GetCFObjectHandle (handle, "kCFBooleanTrue"), false);
1276                                 False = new CFBoolean (CFObject.GetCFObjectHandle (handle, "kCFBooleanFalse"), false);
1277                         }
1278                         finally {
1279                                 CFObject.dlclose (handle);
1280                         }
1281                 }
1282
1283                 internal CFBoolean (IntPtr handle, bool owns)
1284                 {
1285                         this.handle = handle;
1286                         if (!owns)
1287                                 CFObject.CFRetain (handle);
1288                 }
1289
1290                 ~CFBoolean ()
1291                 {
1292                         Dispose (false);
1293                 }
1294
1295                 public IntPtr Handle {
1296                         get {
1297                                 return handle;
1298                         }
1299                 }
1300
1301                 public void Dispose ()
1302                 {
1303                         Dispose (true);
1304                         GC.SuppressFinalize (this);
1305                 }
1306
1307                 protected virtual void Dispose (bool disposing)
1308                 {
1309                         if (handle != IntPtr.Zero){
1310                                 CFObject.CFRelease (handle);
1311                                 handle = IntPtr.Zero;
1312                         }
1313                 }
1314
1315                 public static implicit operator bool (CFBoolean value)
1316                 {
1317                         return value.Value;
1318                 }
1319
1320                 public static explicit operator CFBoolean (bool value)
1321                 {
1322                         return FromBoolean (value);
1323                 }
1324
1325                 public static CFBoolean FromBoolean (bool value)
1326                 {
1327                         return value ? True : False;
1328                 }
1329
1330                 [DllImport (CFObject.CoreFoundationLibrary)]
1331                 [return: MarshalAs (UnmanagedType.I1)]
1332                 extern static /* Boolean */ bool CFBooleanGetValue (/* CFBooleanRef */ IntPtr boolean);
1333
1334                 public bool Value {
1335                         get {return CFBooleanGetValue (handle);}
1336                 }
1337
1338                 public static bool GetValue (IntPtr boolean)
1339                 {
1340                         return CFBooleanGetValue (boolean);
1341                 }
1342         }
1343
1344         internal class CFDate : INativeObject, IDisposable {
1345                 IntPtr handle;
1346
1347                 internal CFDate (IntPtr handle, bool owns)
1348                 {
1349                         this.handle = handle;
1350                         if (!owns)
1351                                 CFObject.CFRetain (handle);
1352                 }
1353
1354                 ~CFDate ()
1355                 {
1356                         Dispose (false);
1357                 }
1358
1359                 [DllImport (CFObject.CoreFoundationLibrary)]
1360                 extern static IntPtr CFDateCreate (IntPtr allocator, /* CFAbsoluteTime */ double at);
1361
1362                 public static CFDate Create (DateTime date)
1363                 {
1364                         var referenceTime = new DateTime (2001, 1, 1);
1365                         var difference = (date - referenceTime).TotalSeconds;
1366                         var handle = CFDateCreate (IntPtr.Zero, difference);
1367                         if (handle == IntPtr.Zero)
1368                                 throw new NotSupportedException ();
1369                         return new CFDate (handle, true);
1370                 }
1371
1372                 public IntPtr Handle {
1373                         get {
1374                                 return handle;
1375                         }
1376                 }
1377
1378                 public void Dispose ()
1379                 {
1380                         Dispose (true);
1381                         GC.SuppressFinalize (this);
1382                 }
1383
1384                 protected virtual void Dispose (bool disposing)
1385                 {
1386                         if (handle != IntPtr.Zero) {
1387                                 CFObject.CFRelease (handle);
1388                                 handle = IntPtr.Zero;
1389                         }
1390                 }
1391
1392         }
1393
1394 }