Statistics
| Branch: | Revision:

root / trunk / NetSparkle / NetSparkle.cs @ 311d1cde

History | View | Annotate | Download (26.2 kB)

1
using System;
2
using System.ComponentModel;
3
using System.Reflection;
4
using System.Threading;
5
using System.Net;
6
using System.Windows.Forms;
7
using System.Drawing;
8
using System.Security.Cryptography.X509Certificates;
9
using System.Net.Security;
10
using log4net;
11
using Point = System.Drawing.Point;
12

    
13
namespace AppLimit.NetSparkle
14
{
15
    public delegate void LoopStartedOperation(Object sender);
16
    public delegate void LoopFinishedOperation(Object sender, Boolean UpdateRequired);
17

    
18
    /// <summary>
19
    /// Everytime when netsparkle detects an update the 
20
    /// consumer can decide what should happen as next with the help 
21
    /// of the UpdateDatected event
22
    /// </summary>
23
    public enum nNextUpdateAction
24
    {
25
        showStandardUserInterface = 1,
26
        performUpdateUnattended = 2,
27
        prohibitUpdate = 3
28
    }
29

    
30
    /// <summary>
31
    /// Contains all information for the update detected event
32
    /// </summary>
33
    public class UpdateDetectedEventArgs : EventArgs
34
    {
35
        public nNextUpdateAction NextAction;
36
        public NetSparkleConfiguration ApplicationConfig;
37
        public NetSparkleAppCastItem LatestVersion;        
38
    }
39

    
40
    /// <summary>
41
    /// This delegate will be used when an update was detected to allow library 
42
    /// consumer to add own user interface capabilities.    
43
    /// </summary>
44
    /// <param name="sender"></param>
45
    /// <param name="e"></param>
46
    public delegate void UpdateDetected(Object sender, UpdateDetectedEventArgs e);
47

    
48
    public class Sparkle : IDisposable
49
    {
50
        private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51

    
52
        private BackgroundWorker _worker = new BackgroundWorker();
53

    
54
        private String _AppCastUrl;
55
        private String _AppReferenceAssembly;
56

    
57
        private Boolean _DoInitialCheck;
58
        private Boolean _ForceInitialCheck;
59

    
60
        private EventWaitHandle _exitHandle;
61
        private EventWaitHandle _loopingHandle;
62
        
63
        private NetSparkleMainWindows _DiagnosticWindow;
64

    
65
        private TimeSpan _CheckFrequency;
66

    
67
        /// <summary>
68
        /// Enables system profiling against a profile server
69
        /// </summary>
70
        public Boolean EnableSystemProfiling = false;
71

    
72
        /// <summary>
73
        /// Hides the release notes view when an update was found. This 
74
        /// mode is switched on automatically when no sparkle:releaseNotesLink
75
        /// tag was found in the app cast         
76
        /// </summary>
77
        public Boolean HideReleaseNotes = false;
78

    
79
        /// <summary>
80
        /// Contains the profile url for System profiling
81
        /// </summary>
82
        public Uri SystemProfileUrl;
83

    
84
        /// <summary>
85
        /// This event will be raised when a check loop will be started
86
        /// </summary>
87
        public event LoopStartedOperation checkLoopStarted;
88

    
89
        /// <summary>
90
        /// This event will be raised when a check loop is finished
91
        /// </summary>
92
        public event LoopFinishedOperation checkLoopFinished;
93

    
94
        /// <summary>
95
        /// This event can be used to override the standard user interface
96
        /// process when an update is detected
97
        /// </summary>
98
        public event UpdateDetected updateDetected;
99

    
100
        /// <summary>
101
        /// This property holds an optional application icon
102
        /// which will be displayed in the software update dialog. The icon has
103
        /// to be 48x48 pixels.
104
        /// </summary>
105
        public Image ApplicationIcon { get; set; }
106

    
107
        /// <summary>
108
        /// This property returns an optional application icon 
109
        /// which will displayed in the windows as self
110
        /// </summary>
111
        public Icon ApplicationWindowIcon { get; set; }
112

    
113
        /// <summary>
114
        /// This property enables a diagnostic window for debug reasons
115
        /// </summary>
116
        public Boolean ShowDiagnosticWindow { get; set; }
117

    
118
        /// <summary>
119
        /// This property enables the silent mode, this means 
120
        /// the application will be updated without user interaction
121
        /// </summary>
122
        public Boolean EnableSilentMode { get; set; }
123

    
124
        /// <summary>
125
        /// This property returns true when the upadete loop is running
126
        /// and files when the loop is not running
127
        /// </summary>
128
        public Boolean IsUpdateLoopRunning
129
        {
130
            get
131
            {
132
                return _loopingHandle.WaitOne(0);
133
            }
134
        }
135

    
136
        /// <summary>
137
        /// This property defines if we trust every ssl connection also when 
138
        /// this connection has not a valid cert
139
        /// </summary>
140
        public Boolean TrustEverySSLConnection { get; set; }
141

    
142
        public string LatestVersion { get; set; }
143

    
144
        /// <summary>
145
        /// ctor which needs the appcast url
146
        /// </summary>
147
        /// <param name="appcastUrl"></param>
148
        public Sparkle(String appcastUrl)
149
            : this(appcastUrl, null)
150
        { }
151

    
152
        /// <summary>
153
        /// ctor which needs the appcast url and a referenceassembly
154
        /// </summary>
155
        public Sparkle(String appcastUrl, String referenceAssembly)
156
            : this(appcastUrl, referenceAssembly, false)
157
        { }
158

    
159
        /// <summary>
160
        /// ctor which needs the appcast url and a referenceassembly
161
        /// </summary>        
162
        public Sparkle(String appcastUrl, String referenceAssembly, Boolean ShowDiagnostic)
163
        {
164
            // preconfige ssl trust
165
            TrustEverySSLConnection = false;
166

    
167
            // configure ssl cert link
168
            ServicePointManager.ServerCertificateValidationCallback += RemoteCertificateValidation;
169

    
170
            // enable visual style to ensure that we have XP style or higher
171
            // also in WPF applications
172
            System.Windows.Forms.Application.EnableVisualStyles();
173

    
174
            // reset vars
175
            ApplicationIcon = null;
176
            _AppReferenceAssembly = null;            
177

    
178
            // set var
179
            ShowDiagnosticWindow = ShowDiagnostic;
180

    
181
            // create the diagnotic window
182
            _DiagnosticWindow = new NetSparkleMainWindows();
183

    
184
            // set the reference assembly
185
            if (referenceAssembly != null)
186
            {
187
                _AppReferenceAssembly = referenceAssembly;
188
                _DiagnosticWindow.Report("Checking the following file: " + _AppReferenceAssembly);
189
            }
190

    
191
            // show if needed
192
            ShowDiagnosticWindowIfNeeded();            
193

    
194
            // adjust the delegates
195
            _worker.WorkerReportsProgress = true;
196
            _worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
197
            _worker.ProgressChanged += new ProgressChangedEventHandler(_worker_ProgressChanged);
198

    
199
            // build the wait handle
200
            _exitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
201
            _loopingHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
202

    
203
            // set the url
204
            _AppCastUrl = appcastUrl;
205
            _DiagnosticWindow.Report("Using the following url: " + _AppCastUrl);            
206
        }
207

    
208
        /// <summary>
209
        /// The method starts a NetSparkle background loop
210
        /// If NetSparkle is configured to check for updates on startup, proceeds to perform 
211
        /// the check. You should only call this function when your app is initialized and 
212
        /// shows its main window.        
213
        /// </summary>        
214
        /// <param name="doInitialCheck"></param>
215
        public void StartLoop(Boolean doInitialCheck)
216
        {
217
            StartLoop(doInitialCheck, false);
218
        }
219

    
220
        /// <summary>
221
        /// The method starts a NetSparkle background loop
222
        /// If NetSparkle is configured to check for updates on startup, proceeds to perform 
223
        /// the check. You should only call this function when your app is initialized and 
224
        /// shows its main window.
225
        /// </summary>
226
        /// <param name="doInitialCheck"></param>
227
        /// <param name="checkFrequency"></param>
228
        public void StartLoop(Boolean doInitialCheck, TimeSpan checkFrequency)
229
        {
230
            StartLoop(doInitialCheck, false, checkFrequency);
231
        }
232

    
233
        /// <summary>
234
        /// The method starts a NetSparkle background loop
235
        /// If NetSparkle is configured to check for updates on startup, proceeds to perform 
236
        /// the check. You should only call this function when your app is initialized and 
237
        /// shows its main window.
238
        /// </summary>
239
        /// <param name="doInitialCheck"></param>
240
        /// <param name="forceInitialCheck"></param>
241
        public void StartLoop(Boolean doInitialCheck, Boolean forceInitialCheck)
242
        {
243
            StartLoop(doInitialCheck, forceInitialCheck, TimeSpan.FromHours(24));
244
        }
245

    
246
        /// <summary>
247
        /// The method starts a NetSparkle background loop
248
        /// If NetSparkle is configured to check for updates on startup, proceeds to perform 
249
        /// the check. You should only call this function when your app is initialized and 
250
        /// shows its main window.
251
        /// </summary>
252
        /// <param name="doInitialCheck"></param>
253
        /// <param name="forceInitialCheck"></param>
254
        /// <param name="checkFrequency"></param>
255
        public void StartLoop(Boolean doInitialCheck, Boolean forceInitialCheck, TimeSpan checkFrequency)
256
        {
257
            // first set the event handle
258
            _loopingHandle.Set();
259

    
260
            // Start the helper thread as a background worker to 
261
            // get well ui interaction                        
262

    
263
            // show if needed
264
            ShowDiagnosticWindowIfNeeded();
265

    
266
            // store infos
267
            _DoInitialCheck = doInitialCheck;
268
            _ForceInitialCheck = forceInitialCheck;
269
            _CheckFrequency = checkFrequency;
270

    
271
            // create and configure the worker
272
            _DiagnosticWindow.Report("Starting background worker");
273

    
274
            // start the work
275
            _worker.RunWorkerAsync();
276
        }
277

    
278
        /// <summary>
279
        /// This method will stop the sparkle background loop and is called
280
        /// through the disposable interface automatically
281
        /// </summary>
282
        public void StopLoop()
283
        {
284
            // ensure the work will finished
285
            _exitHandle.Set();                       
286
        }
287

    
288
        /// <summary>
289
        /// Is called in the using context and will stop all background activities
290
        /// </summary>
291
        public void Dispose()
292
        {
293
            StopLoop();
294
        }
295

    
296
        /// <summary>
297
        /// This method updates the profile information which can be sended to the server if enabled    
298
        /// </summary>
299
        /// <param name="config"></param>
300
        public void UpdateSystemProfileInformation(NetSparkleConfiguration config)
301
        {
302
            // check if profile data is enabled
303
            if (!EnableSystemProfiling)
304
                return;
305

    
306
            // check if we need an update
307
            if (DateTime.Now - config.LastProfileUpdate < new TimeSpan(7, 0, 0, 0))
308
                return;
309

    
310
            // touch the profile update time
311
            config.TouchProfileTime();
312

    
313
            // start the profile thread
314
            Thread t = new Thread(ProfileDataThreadStart);
315
            t.Start(config);
316
        }
317

    
318
        /// <summary>
319
        /// Profile data thread
320
        /// </summary>
321
        /// <param name="obj"></param>
322
        private void ProfileDataThreadStart(object obj)
323
        {
324
            try
325
            {
326
                if (SystemProfileUrl != null)
327
                {
328
                    // get the config
329
                    NetSparkleConfiguration config = obj as NetSparkleConfiguration;
330

    
331
                    // collect data
332
                    NetSparkleDeviceInventory inv = new NetSparkleDeviceInventory(config);
333
                    inv.CollectInventory();
334

    
335
                    // build url
336
                    String requestUrl = inv.BuildRequestUrl(SystemProfileUrl.ToString() + "?");
337

    
338
                    HttpWebRequest.DefaultWebProxy = HttpWebRequest.GetSystemWebProxy();
339

    
340
                    // perform the webrequest
341
                    HttpWebRequest request = HttpWebRequest.Create(requestUrl) as HttpWebRequest;
342
                    using (WebResponse response = request.GetResponse())
343
                    {
344
                        // close the response 
345
                        response.Close();
346
                    }
347
                }
348
            }
349
            catch (Exception ex)
350
            {
351
                // No exception during data send 
352
                ReportDiagnosticMessage(ex.Message);
353
            }
354
        }
355

    
356
        /// <summary>
357
        /// This method checks if an update is required. During this process the appcast
358
        /// will be downloaded and checked against the reference assembly. Ensure that
359
        /// the calling process has access to the internet and read access to the 
360
        /// reference assembly. This method is also called from the background loops.
361
        /// </summary>
362
        /// <param name="config"></param>
363
        /// <returns></returns>
364
        public Boolean IsUpdateRequired(NetSparkleConfiguration config, out NetSparkleAppCastItem latestVersion)
365
        {
366
            // report
367
            ReportDiagnosticMessage("Downloading and checking appcast");
368

    
369
            // init the appcast
370
            NetSparkleAppCast cast = new NetSparkleAppCast(_AppCastUrl, config);
371

    
372
            // check if any updates are available
373
            try
374
            {
375
                latestVersion = cast.GetLatestVersion();
376
            }
377
            catch (Exception e)
378
            {
379
                // show the exeception message 
380
                ReportDiagnosticMessage("Error during app cast download: " + e.Message);
381

    
382
                // just null the version info
383
                latestVersion = null;
384
            }
385

    
386
            if (latestVersion == null)
387
            {
388
                ReportDiagnosticMessage("No version information in app cast found");
389
                return false;
390
            }
391
            else
392
            {
393
                ReportDiagnosticMessage("Lastest version on the server is " + latestVersion.Version);
394
            }
395

    
396
            // set the last check time
397
            ReportDiagnosticMessage("Touch the last check timestamp");
398
            config.TouchCheckTime();
399

    
400
            // check if the available update has to be skipped
401
            if (latestVersion.Version.Equals(config.SkipThisVersion))
402
            {
403
                ReportDiagnosticMessage("Latest update has to be skipped (user decided to skip version " + config.SkipThisVersion + ")");
404
                return false;
405
            }
406

    
407
            // check if the version will be the same then the installed version
408
            Version v1 = new Version(config.InstalledVersion);
409
            Version v2 = new Version(latestVersion.Version);
410

    
411
            if (v2 <= v1)
412
            {
413
                ReportDiagnosticMessage("Installed version is valid, no update needed (" + config.InstalledVersion + ")");
414
                return false;
415
            }
416

    
417
            // ok we need an update
418
            return true;
419
        }
420

    
421
        /// <summary>
422
        /// This method reads the local sparkle configuration for the given
423
        /// reference assembly
424
        /// </summary>
425
        /// <param name="AppReferenceAssembly"></param>
426
        /// <returns></returns>
427
        public NetSparkleConfiguration GetApplicationConfig()
428
        {
429
            NetSparkleConfiguration config;
430
            config = new NetSparkleConfiguration(_AppReferenceAssembly);
431
            return config;
432
        }
433

    
434
        /// <summary>
435
        /// This method shows the update ui and allows to perform the 
436
        /// update process
437
        /// </summary>
438
        /// <param name="currentItem"></param>
439
        public void ShowUpdateNeededUI(NetSparkleAppCastItem currentItem)
440
        {
441

    
442
            // create the form
443
            NetSparkleForm frm = new NetSparkleForm(currentItem, ApplicationIcon, ApplicationWindowIcon);
444

    
445
            // configure the form
446
            frm.TopMost = true;
447

    
448
            if (HideReleaseNotes)
449
                frm.RemoveReleaseNotesControls();
450

    
451
            
452
            // show it
453
            DialogResult dlgResult = frm.ShowDialog();
454
            
455

    
456
            if (dlgResult == DialogResult.No)
457
            {
458
                // skip this version
459
                NetSparkleConfiguration config = new NetSparkleConfiguration(_AppReferenceAssembly);
460
                config.SetVersionToSkip(currentItem.Version);
461
            }
462
            else if (dlgResult == DialogResult.Yes)
463
            {
464
                // download the binaries
465
                InitDownloadAndInstallProcess(currentItem);
466
            }
467
            
468
        }
469

    
470
        /// <summary>
471
        /// This method reports a message in the diagnostic window
472
        /// </summary>
473
        /// <param name="message"></param>
474
        public void ReportDiagnosticMessage(String message)
475
        {
476
            Log.Info(message);
477
            if (_DiagnosticWindow.InvokeRequired)
478
            {
479
                _DiagnosticWindow.Invoke(new Action<String>(ReportDiagnosticMessage), message);                
480
            }
481
            else
482
            {
483
                _DiagnosticWindow.Report(message);
484
            }
485
        }
486

    
487
        /// <summary>
488
        /// This method will be executed as worker thread
489
        /// </summary>
490
        /// <param name="sender"></param>
491
        /// <param name="e"></param>
492
        void _worker_DoWork(object sender, DoWorkEventArgs e)
493
        {
494
            // store the did run once feature
495
            Boolean goIntoLoop = true;
496
            Boolean checkTSP = true;
497
            Boolean doInitialCheck = _DoInitialCheck;
498
            Boolean isInitialCheck = true;
499

    
500
            // start our lifecycles
501
            do
502
            {
503
                // set state
504
                Boolean bUpdateRequired = false;
505

    
506
                // notify
507
                if (checkLoopStarted != null)
508
                    checkLoopStarted(this);
509

    
510
                // report status
511
                if (doInitialCheck == false)
512
                {
513
                    ReportDiagnosticMessage("Initial check prohibited, going to wait");
514
                    doInitialCheck = true;
515
                    goto WaitSection;
516
                }
517

    
518
                // report status
519
                ReportDiagnosticMessage("Starting update loop...");
520

    
521
                // read the config
522
                ReportDiagnosticMessage("Reading config...");
523
                NetSparkleConfiguration config = GetApplicationConfig();
524

    
525
                // calc CheckTasp
526
                Boolean checkTSPInternal = checkTSP;
527

    
528
                if (isInitialCheck && checkTSPInternal)
529
                    checkTSPInternal = !_ForceInitialCheck;
530

    
531
                // check if it's ok the recheck to software state
532
                if (checkTSPInternal)
533
                {
534
                    TimeSpan csp = DateTime.Now - config.LastCheckTime;
535
                    if (csp < _CheckFrequency)
536
                    {
537
                        ReportDiagnosticMessage(String.Format("Update check performed within the last {0} minutes!", _CheckFrequency.TotalMinutes));
538
                        goto WaitSection;
539
                    }
540
                }
541
                else
542
                    checkTSP = true;
543

    
544
                // when sparkle will be deactivated wait an other cycle
545
                if (config.CheckForUpdate == false)
546
                {
547
                    ReportDiagnosticMessage("Check for updates disabled");
548
                    goto WaitSection;
549
                }
550

    
551
                // update the runonce feature
552
                goIntoLoop = !config.DidRunOnce;
553

    
554
                // update profile information is needed
555
                UpdateSystemProfileInformation(config);
556

    
557
                // check if update is required
558
                NetSparkleAppCastItem latestVersion = null;
559
                bUpdateRequired = IsUpdateRequired(config, out latestVersion);
560
                this.LatestVersion = latestVersion.Version??"";                
561
                if (!bUpdateRequired)
562
                    goto WaitSection;
563

    
564
                // show the update window
565
                ReportDiagnosticMessage("Update needed from version " + config.InstalledVersion + " to version " + latestVersion.Version);
566

    
567
                // send notification if needed
568
                UpdateDetectedEventArgs ev = new UpdateDetectedEventArgs() { NextAction = nNextUpdateAction.showStandardUserInterface, ApplicationConfig = config, LatestVersion = latestVersion };
569
                if (updateDetected != null)
570
                    updateDetected(this, ev);
571
                
572
                // check results
573
                switch(ev.NextAction)
574
                {
575
                    case nNextUpdateAction.performUpdateUnattended:
576
                        {
577
                            ReportDiagnosticMessage("Unattended update whished from consumer");
578
                            EnableSilentMode = true;
579
                            _worker.ReportProgress(1, latestVersion);
580
                            break;
581
                        }
582
                    case nNextUpdateAction.prohibitUpdate:
583
                        {
584
                            ReportDiagnosticMessage("Update prohibited from consumer");
585
                            break;
586
                        }
587
                    case nNextUpdateAction.showStandardUserInterface:
588
                    default:
589
                        {
590
                            ReportDiagnosticMessage("Standard UI update whished from consumer");
591
                            _worker.ReportProgress(1, latestVersion);
592
                            break;
593
                        }
594
                }                
595

    
596
            WaitSection:
597
                // reset initialcheck
598
                isInitialCheck = false;
599

    
600
                // notify
601
                if (checkLoopFinished != null)
602
                    checkLoopFinished(this, bUpdateRequired);
603

    
604
                // report wait statement
605
                ReportDiagnosticMessage(String.Format("Sleeping for an other {0} minutes, exit event or force update check event", _CheckFrequency.TotalMinutes));
606

    
607
                // wait for
608
                if (!goIntoLoop)
609
                    break;
610
                else
611
                {
612
                    // build the event array
613
                    WaitHandle[] handles = new WaitHandle[1];
614
                    handles[0] = _exitHandle;
615

    
616
                    // wait for any
617
                    int i = WaitHandle.WaitAny(handles, _CheckFrequency);
618
                    if (WaitHandle.WaitTimeout == i)
619
                    {
620
                        ReportDiagnosticMessage(String.Format("{0} minutes are over", _CheckFrequency.TotalMinutes));
621
                        continue;
622
                    }
623

    
624
                    // check the exit hadnle
625
                    if (i == 0)
626
                    {
627
                        ReportDiagnosticMessage("Got exit signal");
628
                        break;
629
                    }
630

    
631
                    // check an other check needed
632
                    if (i == 1)
633
                    {
634
                        ReportDiagnosticMessage("Got force update check signal");
635
                        checkTSP = false;
636
                        continue;
637
                    }
638
                }
639
            } while (goIntoLoop);
640

    
641
            // reset the islooping handle
642
            _loopingHandle.Reset();
643
        }
644

    
645
        /// <summary>
646
        /// This method will be notified
647
        /// </summary>
648
        /// <param name="sender"></param>
649
        /// <param name="e"></param>
650
        private void _worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
651
        {
652
            switch (e.ProgressPercentage)
653
            {
654
                case 1:
655
                    {
656
                        // get the current item
657
                        NetSparkleAppCastItem currentItem = e.UserState as NetSparkleAppCastItem;
658

    
659
                        // show the update ui
660
                        if (EnableSilentMode == true)
661
                            InitDownloadAndInstallProcess(currentItem);
662
                        else
663
                            ShowUpdateNeededUI(currentItem);
664

    
665
                        break;
666
                    }
667
                case 0:
668
                    {
669
                        ReportDiagnosticMessage(e.UserState.ToString());
670
                        break;
671
                    }
672
            }
673
        }
674

    
675
        private void InitDownloadAndInstallProcess(NetSparkleAppCastItem item)
676
        {
677
            NetSparkleDownloadProgress dlProgress = new NetSparkleDownloadProgress(this, item, _AppReferenceAssembly, ApplicationIcon, ApplicationWindowIcon, EnableSilentMode);
678
            dlProgress.ShowDialog();
679
        }
680

    
681
        private void ShowDiagnosticWindowIfNeeded()
682
        {
683
            if (_DiagnosticWindow.InvokeRequired)
684
            {
685
                _DiagnosticWindow.Invoke(new Action(ShowDiagnosticWindowIfNeeded));
686
            }
687
            else
688
            {
689
                // check the diagnotic value
690
                NetSparkleConfiguration config = new NetSparkleConfiguration(_AppReferenceAssembly);
691
                if (config.ShowDiagnosticWindow || ShowDiagnosticWindow)
692
                {
693
                    Point newLocation = new Point();
694

    
695
                    newLocation.X = Screen.PrimaryScreen.Bounds.Width - _DiagnosticWindow.Width;
696
                    newLocation.Y = 0;
697

    
698
                    _DiagnosticWindow.Location = newLocation;
699
                    _DiagnosticWindow.Show();
700
                }
701
            }
702
        }
703

    
704
        private bool RemoteCertificateValidation(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
705
        {
706
            if (TrustEverySSLConnection)
707
            {
708
                // verify if we talk about our app cast dll 
709
                HttpWebRequest req = sender as HttpWebRequest;
710
                if (req == null)
711
                    return (certificate is X509Certificate2) ? ((X509Certificate2)certificate).Verify() : false;
712

    
713
                // if so just return our trust 
714
                if (req.RequestUri.Equals(new Uri(_AppCastUrl)))
715
                    return true;
716
                else
717
                    return (certificate is X509Certificate2) ? ((X509Certificate2)certificate).Verify() : false;
718
            }
719
            else
720
            {
721
                // check our cert                 
722
                return (certificate is X509Certificate2) ? ((X509Certificate2)certificate).Verify() : false;
723
            }
724
        }
725
    }
726
}