2017-05-23 10:24:56 +02:00
using System ;
2011-06-06 18:48:52 +00:00
using System.Collections.Generic ;
using System.Linq ;
2017-05-02 21:14:28 +02:00
using System.Net ;
2017-06-29 00:08:02 +02:00
using Duplicati.Library.Interface ;
2011-06-06 18:48:52 +00:00
namespace Duplicati.GUI.TrayIcon
{
2011-11-28 11:05:42 +00:00
public static class Program
2011-06-06 18:48:52 +00:00
{
2018-02-25 13:54:20 +01:00
public enum PasswordSource
{
Database ,
HostedServer
}
2011-11-21 22:28:20 +00:00
public static HttpServerConnection Connection ;
2014-07-07 01:33:19 +02:00
2011-11-23 20:52:28 +00:00
private const string TOOLKIT_OPTION = "toolkit" ;
private const string TOOLKIT_WINDOWS_FORMS = "winforms" ;
private const string TOOLKIT_GTK = "gtk" ;
2011-11-28 11:05:42 +00:00
private const string TOOLKIT_GTK_APP_INDICATOR = "gtk-appindicator" ;
2011-11-23 20:52:28 +00:00
private const string TOOLKIT_COCOA = "cocoa" ;
2016-04-07 21:00:02 +02:00
private const string TOOLKIT_RUMPS = "rumps" ;
2012-07-14 10:42:48 +00:00
private const string HOSTURL_OPTION = "hosturl" ;
private const string NOHOSTEDSERVER_OPTION = "no-hosted-server" ;
2017-05-02 21:14:28 +02:00
private const string READCONFIGFROMDB_OPTION = "read-config-from-db" ;
2017-10-11 08:57:12 +02:00
private const string DETACHED_PROCESS = "detached-process" ;
2014-03-27 15:24:38 +01:00
private const string BROWSER_COMMAND_OPTION = "browser-command" ;
2012-07-14 10:42:48 +00:00
2017-03-06 14:26:40 +01:00
private const string DEFAULT_HOSTURL = "http://localhost:8200" ;
2011-11-28 11:05:42 +00:00
2014-03-27 15:24:38 +01:00
private static string _browser_command = null ;
public static string BrowserCommand { get { return _browser_command ; } }
2017-05-02 21:39:04 +02:00
public static Server . Database . Connection databaseConnection = null ;
2017-05-02 21:14:28 +02:00
2016-03-22 00:15:17 +01:00
private static string GetDefaultToolKit ( bool printwarnings )
2011-11-28 11:05:42 +00:00
{
2016-09-23 14:11:53 +02:00
// No longer using Cocoa directly as it fails on 32bit as well
2014-07-07 01:33:19 +02:00
if ( Duplicati . Library . Utility . Utility . IsClientOSX )
2017-06-17 18:46:38 +02:00
return TOOLKIT_RUMPS ;
2017-05-23 10:17:55 +02:00
#if __MonoCS__ || __WindowsGTK__ || ENABLE_GTK
2011-12-15 09:38:58 +00:00
if ( Duplicati . Library . Utility . Utility . IsClientLinux )
2011-11-28 11:05:42 +00:00
{
if ( SupportsAppIndicator )
return TOOLKIT_GTK_APP_INDICATOR ;
else
return TOOLKIT_GTK ;
}
else
2014-03-20 15:31:01 +01:00
#endif
2017-09-18 23:23:45 -06:00
{
2011-11-28 11:05:42 +00:00
//Windows users expect a WinForms element
return TOOLKIT_WINDOWS_FORMS ;
}
}
2014-06-26 22:37:58 +02:00
2011-06-06 18:48:52 +00:00
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
2014-06-26 22:37:58 +02:00
public static int Main ( string [] args )
{
2014-07-02 15:00:27 +02:00
Duplicati . Library . AutoUpdater . UpdaterManager . RequiresRespawn = true ;
2014-07-02 20:46:50 +02:00
return Duplicati . Library . AutoUpdater . UpdaterManager . RunFromMostRecent ( typeof ( Program ). GetMethod ( "RealMain" ), args , Duplicati . Library . AutoUpdater . AutoUpdateStrategy . Never );
2014-06-26 22:37:58 +02:00
}
public static void RealMain ( string [] _args )
2011-06-06 18:48:52 +00:00
{
2011-11-23 20:52:28 +00:00
List < string > args = new List < string >( _args );
2011-11-28 11:05:42 +00:00
Dictionary < string , string > options = Duplicati . Library . Utility . CommandLineParser . ExtractOptions ( args );
2014-04-02 11:34:33 +02:00
2017-10-11 12:49:14 +02:00
if ( Duplicati . Library . Utility . Utility . IsClientWindows && ( Duplicati . Library . AutoUpdater . UpdaterManager . IsRunningInUpdateEnvironment || ! Duplicati . Library . Utility . Utility . ParseBoolOption ( options , DETACHED_PROCESS )))
2017-10-11 08:57:12 +02:00
Duplicati . Library . Utility . Win32 . AttachConsole ( Duplicati . Library . Utility . Win32 . ATTACH_PARENT_PROCESS );
2014-04-02 11:34:33 +02:00
foreach ( string s in args )
if (
2017-09-18 23:23:45 -06:00
s . Equals ( "help" , StringComparison . OrdinalIgnoreCase ) ||
s . Equals ( "/help" , StringComparison . OrdinalIgnoreCase ) ||
s . Equals ( "usage" , StringComparison . OrdinalIgnoreCase ) ||
s . Equals ( "/usage" , StringComparison . OrdinalIgnoreCase ))
2014-04-02 11:34:33 +02:00
options [ "help" ] = "" ;
if ( options . ContainsKey ( "help" ))
{
2014-07-07 01:33:19 +02:00
Console . WriteLine ( "Supported commandline arguments:" );
Console . WriteLine ();
2014-04-02 11:34:33 +02:00
foreach ( Library . Interface . ICommandLineArgument arg in SupportedCommands )
2017-05-23 10:17:55 +02:00
{
2017-06-17 18:46:38 +02:00
Console . WriteLine ( "--{0}: {1}" , arg . Name , arg . LongDescription );
2017-09-18 23:23:45 -06:00
if ( arg . Name == TOOLKIT_OPTION )
2017-06-17 18:46:38 +02:00
Console . WriteLine ( " Supported toolkits: {0}{1}" , string . Join ( ", " , arg . ValidValues ), Environment . NewLine );
2017-09-18 23:23:45 -06:00
}
2014-04-02 11:34:33 +02:00
2014-07-07 01:33:19 +02:00
Console . WriteLine ( "Additionally, these server options are also supported:" );
Console . WriteLine ();
2014-04-02 11:34:33 +02:00
foreach ( Library . Interface . ICommandLineArgument arg in Duplicati . Server . Program . SupportedCommands )
2014-07-07 01:33:19 +02:00
Console . WriteLine ( "--{0}: {1}" , arg . Name , arg . LongDescription );
2014-04-02 11:34:33 +02:00
return ;
2017-06-22 15:10:31 +02:00
}
2014-03-27 15:24:38 +01:00
options . TryGetValue ( BROWSER_COMMAND_OPTION , out _browser_command );
2011-11-23 20:52:28 +00:00
string toolkit ;
if (! options . TryGetValue ( TOOLKIT_OPTION , out toolkit ))
2017-06-17 18:46:38 +02:00
{
2017-05-23 10:24:56 +02:00
#if !( __MonoCS__ || __WindowsGTK__ || ENABLE_GTK )
2017-09-18 23:23:45 -06:00
if ( Library . Utility . Utility . IsClientLinux && ! Library . Utility . Utility . IsClientOSX )
Console . WriteLine ( "Warning: this build does not support GTK, rebuild with ENABLE_GTK defined" );
2017-05-23 10:24:56 +02:00
#endif
2017-09-18 23:23:45 -06:00
toolkit = GetDefaultToolKit ( true );
2017-05-23 10:24:56 +02:00
}
2011-11-23 20:52:28 +00:00
else
{
2017-09-18 23:23:45 -06:00
if ( TOOLKIT_WINDOWS_FORMS . Equals ( toolkit , StringComparison . OrdinalIgnoreCase ))
2017-06-17 18:46:38 +02:00
toolkit = TOOLKIT_WINDOWS_FORMS ;
2017-05-23 10:17:55 +02:00
#if __MonoCS__ || __WindowsGTK__ || ENABLE_GTK
2017-09-18 23:23:45 -06:00
else if ( TOOLKIT_GTK . Equals ( toolkit , StringComparison . OrdinalIgnoreCase ))
2011-11-23 20:52:28 +00:00
toolkit = TOOLKIT_GTK ;
2017-09-18 23:23:45 -06:00
else if ( TOOLKIT_GTK_APP_INDICATOR . Equals ( toolkit , StringComparison . OrdinalIgnoreCase ))
2011-11-28 11:05:42 +00:00
toolkit = TOOLKIT_GTK_APP_INDICATOR ;
2014-07-07 01:33:19 +02:00
#endif
2017-09-18 23:23:45 -06:00
else if ( TOOLKIT_COCOA . Equals ( toolkit , StringComparison . OrdinalIgnoreCase ))
2011-11-23 20:52:28 +00:00
toolkit = TOOLKIT_COCOA ;
2017-09-18 23:23:45 -06:00
else if ( TOOLKIT_RUMPS . Equals ( toolkit , StringComparison . OrdinalIgnoreCase ))
2016-04-07 21:00:02 +02:00
toolkit = TOOLKIT_RUMPS ;
2011-11-23 20:52:28 +00:00
else
2016-03-22 00:15:17 +01:00
toolkit = GetDefaultToolKit ( true );
2011-11-23 20:52:28 +00:00
}
2014-03-21 10:34:34 +01:00
HostedInstanceKeeper hosted = null ;
2017-05-02 21:14:28 +02:00
var openui = false ;
2014-06-27 13:23:05 +02:00
string password = null ;
2017-05-02 21:14:28 +02:00
var saltedpassword = false ;
var serverURL = new Uri ( DEFAULT_HOSTURL );
2014-03-21 10:34:34 +01:00
if (! Library . Utility . Utility . ParseBoolOption ( options , NOHOSTEDSERVER_OPTION ))
{
try
{
hosted = new HostedInstanceKeeper ( _args );
}
catch ( Server . SingleInstance . MultipleInstanceException )
{
return ;
}
2014-06-23 11:22:54 +02:00
// We have a hosted server, if this is the first run,
// we should open the main page
openui = Duplicati . Server . Program . IsFirstRun || Duplicati . Server . Program . ServerPortChanged ;
2014-06-27 13:23:05 +02:00
password = Duplicati . Server . Program . DataConnection . ApplicationSettings . WebserverPassword ;
saltedpassword = true ;
2018-03-09 21:24:57 +01:00
// Tell the hosted server it was started by the TrayIcon
Duplicati . Server . Program . Origin = "Tray icon" ;
2018-02-25 13:54:20 +01:00
var cert = Duplicati . Server . Program . DataConnection . ApplicationSettings . ServerSSLCertificate ;
var scheme = "http" ;
if ( cert != null && cert . HasPrivateKey )
scheme = "https" ;
serverURL = ( new UriBuilder ( serverURL )
{
Port = Duplicati . Server . Program . ServerPort ,
Scheme = scheme
}). Uri ;
2017-05-02 21:14:28 +02:00
}
if ( Library . Utility . Utility . ParseBoolOption ( options , NOHOSTEDSERVER_OPTION ) && Library . Utility . Utility . ParseBoolOption ( options , READCONFIGFROMDB_OPTION ))
2017-05-21 19:25:39 +02:00
databaseConnection = Server . Program . GetDatabaseConnection ( options );
2017-05-02 21:14:28 +02:00
2017-05-02 21:39:04 +02:00
if ( databaseConnection != null )
2017-05-02 21:14:28 +02:00
{
2017-05-02 21:39:04 +02:00
password = databaseConnection . ApplicationSettings . WebserverPasswordTrayIcon ;
2017-05-02 21:14:28 +02:00
saltedpassword = false ;
2017-06-29 22:47:21 +02:00
var cert = databaseConnection . ApplicationSettings . ServerSSLCertificate ;
var scheme = "http" ;
if ( cert != null && cert . HasPrivateKey )
scheme = "https" ;
serverURL = ( new UriBuilder ( serverURL )
{
Port = databaseConnection . ApplicationSettings . LastWebserverPort == - 1 ? serverURL . Port : databaseConnection . ApplicationSettings . LastWebserverPort ,
Scheme = scheme
}). Uri ;
}
2014-03-21 10:34:34 +01:00
2018-02-25 13:54:20 +01:00
string pwd ;
if ( options . TryGetValue ( "webserver-password" , out pwd ))
{
password = pwd ;
saltedpassword = false ;
}
2017-05-03 00:56:41 +02:00
string url ;
if ( options . TryGetValue ( HOSTURL_OPTION , out url ))
2017-05-02 21:14:28 +02:00
serverURL = new Uri ( url );
2017-06-28 23:45:56 +02:00
2014-03-21 10:34:34 +01:00
using ( hosted )
2011-11-21 22:28:20 +00:00
{
2017-05-03 00:03:16 +02:00
var reSpawn = 0 ;
2017-05-02 21:14:28 +02:00
do
2012-07-14 10:42:48 +00:00
{
2017-05-02 21:14:28 +02:00
try
2012-07-14 10:42:48 +00:00
{
2017-06-28 23:45:56 +02:00
System . Net . ServicePointManager . SecurityProtocol |= SecurityProtocolType . Tls11 | SecurityProtocolType . Tls12 ;
2018-02-25 13:54:20 +01:00
using ( Connection = new HttpServerConnection ( serverURL , password , saltedpassword , databaseConnection != null ? PasswordSource . Database : PasswordSource . HostedServer , options ))
2017-05-02 21:14:28 +02:00
{
using ( var tk = RunTrayIcon ( toolkit ))
{
if ( hosted != null && Server . Program . Instance != null )
Server . Program . Instance . SecondInstanceDetected +=
new Server . SingleInstance . SecondInstanceDelegate (
x => { tk . ShowUrlInWindow ( serverURL . ToString ()); });
// TODO: If we change to hosted browser this should be a callback
if ( openui )
{
try
{
tk . ShowUrlInWindow ( Connection . StatusWindowURL );
Duplicati . Server . Program . IsFirstRun = false ;
Duplicati . Server . Program . ServerPortChanged = false ;
}
catch
{
}
}
// If the server shuts down, shut down the tray-icon as well
Action shutdownEvent = () =>
{
2017-06-27 15:05:46 +02:00
// Make sure we do not start again after
// a controlled exit
reSpawn = 100 ;
2017-05-02 21:14:28 +02:00
tk . InvokeExit ();
};
if ( hosted != null )
hosted . InstanceShutdown += shutdownEvent ;
tk . Init ( _args );
2017-06-27 15:05:46 +02:00
// If the tray-icon quits, stop the server
reSpawn = 100 ;
2017-05-02 21:14:28 +02:00
// Make sure that the server shutdown does not access the tray-icon,
// as it would be disposed by now
if ( hosted != null )
hosted . InstanceShutdown -= shutdownEvent ;
}
}
2012-07-14 10:42:48 +00:00
}
2017-05-02 21:14:28 +02:00
catch ( WebException ex )
2012-07-14 10:42:48 +00:00
{
2017-11-26 15:24:53 -08:00
System . Diagnostics . Trace . WriteLine ( "Request error: " + ex );
Console . WriteLine ( "Request error: " + ex );
2017-05-03 00:03:16 +02:00
reSpawn ++;
2012-07-14 10:42:48 +00:00
}
2017-06-22 15:10:31 +02:00
catch ( Exception ex )
{
2017-11-26 15:24:53 -08:00
System . Diagnostics . Trace . WriteLine ( "Unexpected error: " + ex );
Console . WriteLine ( "Unexpected error: " + ex );
2017-06-23 11:33:03 +02:00
return ;
2017-06-22 15:10:31 +02:00
}
2017-05-03 00:03:16 +02:00
} while ( reSpawn < 3 );
2017-05-02 21:14:28 +02:00
}
}
2011-11-28 11:05:42 +00:00
private static TrayIconBase RunTrayIcon ( string toolkit )
{
if ( toolkit == TOOLKIT_WINDOWS_FORMS )
2017-06-17 18:46:38 +02:00
return GetWinformsInstance ();
2017-05-23 10:17:55 +02:00
#if __MonoCS__ || __WindowsGTK__ || ENABLE_GTK
2011-11-28 11:05:42 +00:00
else if ( toolkit == TOOLKIT_GTK )
return GetGtkInstance ();
else if ( toolkit == TOOLKIT_GTK_APP_INDICATOR )
return GetAppIndicatorInstance ();
2014-07-07 01:33:19 +02:00
#endif
2017-09-18 23:23:45 -06:00
else if ( toolkit == TOOLKIT_COCOA )
2011-11-28 11:05:42 +00:00
return GetCocoaRunnerInstance ();
2016-04-07 21:00:02 +02:00
else if ( toolkit == TOOLKIT_RUMPS )
return GetRumpsRunnerInstance ();
2011-11-28 11:05:42 +00:00
else
2018-03-12 14:07:11 +01:00
throw new UserInformationException ( string . Format ( "The selected toolkit '{0}' is invalid" , toolkit ), "TrayIconInvalidToolKit" );
2011-11-28 11:05:42 +00:00
}
//We keep these in functions to avoid attempting to load the instance,
// because the required assemblies may not exist on the machine
2014-07-08 01:14:20 +02:00
//
//They must be non-inlined even if they are prime candidates,
// as the inlining will pollute the type system and possibly
// attempt to load non-existing assemblies
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
2017-06-17 18:46:38 +02:00
private static TrayIconBase GetWinformsInstance () { return new Windows . WinFormsRunner (); }
2017-05-23 10:17:55 +02:00
#if __MonoCS__ || __WindowsGTK__ || ENABLE_GTK
2014-07-08 01:14:20 +02:00
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
2014-03-20 15:31:01 +01:00
private static TrayIconBase GetGtkInstance () { return new GtkRunner (); }
2014-07-08 01:14:20 +02:00
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
2011-11-28 11:05:42 +00:00
private static TrayIconBase GetAppIndicatorInstance () { return new AppIndicatorRunner (); }
2014-03-20 15:31:01 +01:00
#endif
2017-09-18 23:23:45 -06:00
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
2014-07-07 01:33:19 +02:00
private static TrayIconBase GetCocoaRunnerInstance () { return new CocoaRunner (); }
2016-04-07 21:00:02 +02:00
private static TrayIconBase GetRumpsRunnerInstance () { return new RumpsRunner (); }
2011-11-28 11:05:42 +00:00
//The functions below simply load the requested type,
// and if the type is not present, calling the function will result in an exception.
//This seems to be more reliable than attempting to load the assembly,
// as there are too many complex rules for when an updated assembly is also
// acceptable. This is fairly error proof, as it is just asks the runtime
// to load the required types
2016-04-07 21:00:02 +02:00
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
2011-11-28 11:05:42 +00:00
private static bool TryGetGtk ()
2017-06-17 18:46:38 +02:00
{
2017-05-23 10:17:55 +02:00
#if __MonoCS__ || __WindowsGTK__ || ENABLE_GTK
2011-11-28 11:05:42 +00:00
return typeof ( Gtk . StatusIcon ) != null && typeof ( Gdk . Image ) != null ;
2014-03-20 15:31:01 +01:00
#else
2017-09-18 23:23:45 -06:00
return false ;
2014-03-20 15:31:01 +01:00
#endif
2011-11-28 11:05:42 +00:00
}
2016-04-07 21:00:02 +02:00
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
2011-11-28 11:05:42 +00:00
private static bool TryGetWinforms ()
{
return typeof ( System . Windows . Forms . NotifyIcon ) != null ;
}
2016-04-07 21:00:02 +02:00
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
2011-11-28 11:05:42 +00:00
private static bool TryGetAppIndicator ()
2017-06-17 18:46:38 +02:00
{
2017-05-23 10:17:55 +02:00
#if __MonoCS__ || __WindowsGTK__ || ENABLE_GTK
2014-03-28 13:20:06 +01:00
return typeof ( AppIndicator . ApplicationIndicator ) != null ;
2014-03-20 15:31:01 +01:00
#else
2017-09-18 23:23:45 -06:00
return false ;
2014-03-20 15:31:01 +01:00
#endif
2011-11-28 11:05:42 +00:00
}
2011-11-23 20:52:28 +00:00
2016-04-07 21:00:02 +02:00
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
2011-11-28 11:05:42 +00:00
private static bool TryGetMonoMac ()
{
2016-03-22 00:15:17 +01:00
return ! Environment . Is64BitProcess && typeof ( MonoMac . AppKit . NSApplication ) != null ;
2011-11-28 11:05:42 +00:00
}
//The functions below here, simply wrap the call to the above functions,
// converting the exception to a simple boolean value, so the calling
// code can be kept free of error handling
private static bool SupportsGtk
{
get
{
try { return TryGetGtk (); }
catch {}
return false ;
}
}
private static bool SupportsAppIndicator
{
get
{
try { return TryGetAppIndicator (); }
catch {}
return false ;
}
}
2016-03-22 00:15:17 +01:00
private static bool SupportsCocoa
2011-11-28 11:05:42 +00:00
{
get
{
try { return TryGetMonoMac (); }
catch {}
return false ;
}
}
2016-04-07 21:00:02 +02:00
private static bool SupportsRumps
{
get
{
try { return RumpsRunner . CanRun (); }
catch {}
return false ;
}
}
2011-11-28 11:05:42 +00:00
private static bool SupportsWinForms
{
get
{
try { return TryGetWinforms (); }
catch {}
return false ;
}
}
2011-11-23 20:52:28 +00:00
public static Duplicati . Library . Interface . ICommandLineArgument [] SupportedCommands
{
get
{
2014-04-02 14:00:18 +02:00
var toolkits = new List < string >();
if ( SupportsWinForms )
toolkits . Add ( TOOLKIT_WINDOWS_FORMS );
if ( SupportsGtk )
toolkits . Add ( TOOLKIT_GTK );
if ( SupportsAppIndicator )
toolkits . Add ( TOOLKIT_GTK_APP_INDICATOR );
2016-03-22 00:15:17 +01:00
if ( SupportsCocoa )
2014-04-02 14:00:18 +02:00
toolkits . Add ( TOOLKIT_COCOA );
2016-04-07 21:00:02 +02:00
if ( SupportsRumps )
toolkits . Add ( TOOLKIT_RUMPS );
2014-04-02 14:00:18 +02:00
2017-10-11 08:57:12 +02:00
var args = new List < Duplicati . Library . Interface . ICommandLineArgument >()
2011-11-23 20:52:28 +00:00
{
2016-03-22 00:15:17 +01:00
new Duplicati . Library . Interface . CommandLineArgument ( TOOLKIT_OPTION , CommandLineArgument . ArgumentType . Enumeration , "Selects the toolkit to use" , "Choose the toolkit used to generate the TrayIcon, note that it will fail if the selected toolkit is not supported on this machine" , GetDefaultToolKit ( false ), null , toolkits . ToArray ()),
2012-07-14 10:42:48 +00:00
new Duplicati . Library . Interface . CommandLineArgument ( HOSTURL_OPTION , CommandLineArgument . ArgumentType . String , "Selects the url to connect to" , "Supply the url that the TrayIcon will connect to and show status for" , DEFAULT_HOSTURL ),
new Duplicati . Library . Interface . CommandLineArgument ( NOHOSTEDSERVER_OPTION , CommandLineArgument . ArgumentType . String , "Disables local server" , "Set this option to not spawn a local service, use if the TrayIcon should connect to a running service" ),
2017-05-02 21:14:28 +02:00
new Duplicati . Library . Interface . CommandLineArgument ( READCONFIGFROMDB_OPTION , CommandLineArgument . ArgumentType . String , "Read server connection info from DB" , $"Set this option to read server connection info for running service from its database (only together with {NOHOSTEDSERVER_OPTION})" ),
2017-10-11 08:57:12 +02:00
new Duplicati . Library . Interface . CommandLineArgument ( BROWSER_COMMAND_OPTION , CommandLineArgument . ArgumentType . String , "Sets the browser command" , "Set this option to override the default browser detection" ),
2011-11-23 20:52:28 +00:00
};
2017-10-11 08:57:12 +02:00
if ( Duplicati . Library . Utility . Utility . IsClientWindows )
{
args . Add ( new Duplicati . Library . Interface . CommandLineArgument ( DETACHED_PROCESS , CommandLineArgument . ArgumentType . String , "Runs the tray-icon detached" , "This option runs the tray-icon in detached mode, meaning that the process will exit immediately and not send output to the console of the caller" ));
}
return args . ToArray ();
2011-11-23 20:52:28 +00:00
}
}
2011-06-06 18:48:52 +00:00
}
}