Modified selective sync to propagate the creation of new local directories and their...
[pithos-ms-client] / trunk / Pithos.Client.WPF / App.xaml.cs
1 #region
2 /* -----------------------------------------------------------------------
3  * <copyright file="App.xaml.cs" company="GRNet">
4  * 
5  * Copyright 2011-2012 GRNET S.A. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or
8  * without modification, are permitted provided that the following
9  * conditions are met:
10  *
11  *   1. Redistributions of source code must retain the above
12  *      copyright notice, this list of conditions and the following
13  *      disclaimer.
14  *
15  *   2. Redistributions in binary form must reproduce the above
16  *      copyright notice, this list of conditions and the following
17  *      disclaimer in the documentation and/or other materials
18  *      provided with the distribution.
19  *
20  *
21  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * The views and conclusions contained in the software and
35  * documentation are those of the authors and should not be
36  * interpreted as representing official policies, either expressed
37  * or implied, of GRNET S.A.
38  * </copyright>
39  * -----------------------------------------------------------------------
40  */
41 #endregion
42 using System;
43 using System.Collections.Generic;
44 using System.IO;
45 using System.Linq;
46 using System.Net;
47 using System.Reflection;
48 using System.Text;
49 using System.Threading;
50 using System.Threading.Tasks;
51 using System.Windows;
52 using Caliburn.Micro;
53 using Pithos.Client.WPF.Configuration;
54 using Pithos.Client.WPF.Properties;
55 using Pithos.Interfaces;
56 using log4net.Appender;
57 using log4net.Core;
58 using log4net.Repository.Hierarchy;
59 using System.Runtime.InteropServices;
60
61
62 namespace Pithos.Client.WPF
63 {
64     /// <summary>
65     /// Interaction logic for App.xaml
66     /// </summary>
67     public partial class App : Application
68     {
69         private static readonly log4net.ILog Log = log4net.LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType );
70         
71             ///DLL Import to add restart manager support
72             [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
73             static extern uint RegisterApplicationRestart(string pwzCommandLine, RestartFlags dwFlags);
74                 
75         public App()
76         {
77
78             //var instanceMutex=new Mutex()
79             InitializeLogging();
80
81             ///Register Application in the Restartmanager service
82             RegisterApplicationRestart("Upgrade", RestartFlags.NONE);
83
84
85             DispatcherUnhandledException += OnDispatcherUnhandledException;
86             AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
87             TaskScheduler.UnobservedTaskException += OnUnobservedException;
88
89
90             //Fix incorrect proxy settings by switching to default proxy, if the proxy server settings is empty
91             if (Settings.Default.UseManualProxy && String.IsNullOrWhiteSpace(Settings.Default.ProxyServer))
92             {
93                 Settings.Default.UseManualProxy = false;
94                 Settings.Default.UseDefaultProxy = true;
95             }
96
97             if (Settings.Default.IgnoreCertificateErrors)
98                 ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
99
100
101             InitializeComponent();            
102         }       
103
104
105 /*
106         private void OnUpdateDetected(object sender, UpdateDetectedEventArgs e)
107         {
108             Log.InfoFormat("Update Detected {0}",e.LatestVersion.Version);    
109         }
110 */
111
112         private static void InitializeLogging()
113         {
114             log4net.Config.XmlConfigurator.Configure();
115
116             try
117             {
118                 var pithosDataPath = PithosSettings.PithosDataPath;
119                 if (!Directory.Exists(pithosDataPath))
120                     Directory.CreateDirectory(pithosDataPath);
121
122                 var loggerRepository = (Hierarchy)log4net.LogManager.GetRepository();
123
124                 var appenders = loggerRepository.GetAppenders();
125                 
126
127                 var lossyAppender = appenders.OfType<BufferingForwardingAppender>()
128                     .FirstOrDefault(appender => appender.Name == "LossyFileAppender");
129                 if (lossyAppender!=null)
130                 {
131                     var dumpAppender = lossyAppender.Appenders.OfType<RollingFileAppender>().First();
132                     dumpAppender.File = Path.Combine(pithosDataPath, "errorlog.xml");
133                     dumpAppender.ActivateOptions();
134                 }
135                 
136                 var debugAppender =appenders.OfType<RollingFileAppender>()
137                     .FirstOrDefault(a => a.Name == "DebugFileAppender");
138                 if (debugAppender != null)
139                 {
140                     debugAppender.File = Path.Combine(pithosDataPath, "debuglog.xml");
141                     if (!Settings.Default.DebugLoggingEnabled)
142                         debugAppender.Threshold = Level.Off;
143                     debugAppender.ActivateOptions();
144                 }
145             }
146             catch (Exception exc)
147             {
148                 Log.Error("Dumpl appender initialization failed",exc);                
149             }
150         }
151
152         private Mutex _singleInstanceMutex;
153
154         protected override void OnStartup(StartupEventArgs e)
155         {
156             if (!Settings.Default.StartOnSystemStartup && e.Args.Contains("startup"))
157             {
158                 Shutdown();
159                 return;
160             }
161
162             bool firstInstance;
163             _singleInstanceMutex = new Mutex(false, "PITHOSMUTEX", out firstInstance);
164             if (!firstInstance)
165             {
166                 _singleInstanceMutex.Dispose();
167                 _singleInstanceMutex = null;
168                 Shutdown();
169                 return;
170             }
171
172             //Delay during startup
173             if (e.Args.Contains("startup"))
174             {
175                 if (Settings.Default.StartupDelay>TimeSpan.Zero)
176                     Thread.Sleep(Settings.Default.StartupDelay);
177             }
178
179             var splashScreen = new SplashScreen("images/pithos_logo-title-margin-splash-600-whitebg.png");
180             splashScreen.Show(true);
181             
182             base.OnStartup(e);
183         }
184
185         protected override void OnExit(ExitEventArgs e)
186         {
187             try
188             {
189                 if (_singleInstanceMutex!=null)
190                     _singleInstanceMutex.Dispose();
191                 _singleInstanceMutex = null;
192             }
193             catch { }
194             base.OnExit(e);
195         }
196
197         private void OnUnobservedException(object sender, UnobservedTaskExceptionEventArgs e)
198         {
199             Log.Error("Unobserved Task Exception", e.Exception); 
200             
201             var messages = new List<UserMessage>();
202             e.Exception.Handle(exc=>{
203                 messages.Add(new UserMessage
204                 {
205                     Message = "Unexpected Exception",
206                     Details = exc.ToString(),
207                     Severity = Severity.Error
208                 });
209                 return true;
210             });
211
212
213             //Do not display any messages if this is a 304 code
214             var ignoreExceptions = from exc in e.Exception.InnerExceptions.OfType<WebException>()
215                                    where IsAllowedException(exc)
216                                    select exc;
217
218             if (ignoreExceptions.Any())
219             {
220                 e.SetObserved();
221                 return;
222             }
223
224
225            /* var message = String.Format(@"{0}" + Environment.NewLine + "{1}" + Environment.NewLine + "{2}", 
226                 WPF.Properties.Resources.Unexpected_Error,
227                 WPF.Properties.Resources.We_Apologize, 
228                 WPF.Properties.Resources.Please_Submit_Error);
229             ShowMessages("Oops!",message, messages);*/
230             e.SetObserved();            
231         }
232
233         private bool IsAllowedException(Exception exc)
234         {
235             var we = exc as WebException;
236             if (we==null)
237             {
238                 return false;
239             }
240             var response = we.Response as HttpWebResponse;
241             return (response != null && response.StatusCode == HttpStatusCode.NotModified);
242         }
243
244         private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
245         {
246
247             //Do not display any messages if this is a 304 code
248             if (IsAllowedException(e.ExceptionObject as Exception))
249             {
250                 return;
251             }
252
253             Log.Error("Unhandled exception", (Exception)e.ExceptionObject);
254
255             if (!e.IsTerminating)
256                 //Do not display a message unless the application is terminating
257                 return;
258
259             var description = e.IsTerminating
260                               ? WPF.Properties.Resources.Unexpected_Error_Terminating
261                               : WPF.Properties.Resources.Unexpected_Error;
262             var message = String.Format(@"{0}<LineBreak/>{1}<LineBreak/><LineBreak/>{2}",
263                 description,
264                 WPF.Properties.Resources.We_Apologize,
265                 WPF.Properties.Resources.Please_Submit_Error);
266
267             var exc = ((Exception) e.ExceptionObject);
268             var messages = new[]{
269                                    new UserMessage
270                                        {
271                                            Message = exc.Message,
272                                            Details = exc.ToString(),
273                                            Severity = Severity.Error
274                                        }
275                                };
276
277
278             ShowMessages("Oops!", message,messages);
279         }
280
281
282
283         void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
284         {
285             //Do not display any messages if this is a 304 code
286             if (IsAllowedException(e.Exception))
287             {
288                 return;
289             }
290
291             Log.Error("Unhandled Dispatcher exception", e.Exception);
292             
293            /* var messages = new[]{
294                                    new UserMessage
295                                        {
296                                            Message = e.Exception.Message, 
297                                            Details = e.Exception.ToString(),
298                                            Severity = Severity.Error
299                                        }
300                                };
301             ShowMessages(WPF.Properties.Resources.Error_Title, 
302                 WPF.Properties.Resources.Unexpected_Error,
303                 messages);*/
304             e.Handled=true;
305         }
306
307         void ShowMessages(string title,string message,IEnumerable<UserMessage> messages )
308         {
309             var messageList = messages.ToList();
310             LogMessages(messageList);
311             Execute.OnUIThread(()=>{
312                                        var messageView = new MessageView(messageList)
313                                                         {
314                                                             Title = title, 
315                                                             Message = message
316                                                         };
317                                        messageView.ShowDialog();
318             });
319         }
320
321         private void LogMessages(IEnumerable<UserMessage> messages)
322         {
323             var logMessage = CreateMessage(messages);
324
325             Log.Error(logMessage);
326         }
327
328         private static string CreateMessage(IEnumerable<UserMessage> messages)
329         {
330             var messageBuilder = messages.Aggregate(new StringBuilder("Unexpected Error\r\n"),
331                                                     (builder, message) =>
332                                                         {
333                                                             builder.AppendFormat("\r\n[{0}] {1}\r\n{2}\r\n", message.Severity,
334                                                                                  message.Message, message.Details);
335                                                             return builder;
336                                                         });
337             var logMessage = messageBuilder.ToString();
338             return logMessage;
339         }
340     }
341
342 }
343
344     enum RestartFlags
345     {
346         NONE = 0,
347         RESTART_CYCLICAL = 1,
348         RESTART_NOTIFY_SOLUTION = 2,
349         RESTART_NOTIFY_FAULT = 4,
350         RESTART_NO_CRASH = 8,
351         RESTART_NO_HANG = 16,
352         RESTART_NO_PATCH = 32,
353         RESTART_NO_REBOOT = 64
354     }