1 // rc.cpp: "Run Command" configuration file, for Gnash.
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 // This is generated by autoconf
23 # include "gnashconfig.h"
26 #include "StringPredicates.h"
34 #include <boost/cstdint.hpp>
35 #include <sys/types.h>
36 #include <unistd.h> // for getuid()
39 #include <cstdlib> // getenv
46 #include <boost/format.hpp>
50 # include <FindDirectory.h>
60 RcInitFile::getDefaultInstance()
62 // TODO: allocate on the heap and provide a destroyDefaultInstance,
63 // for finer control of destruction order
64 static RcInitFile rcfile
;
69 RcInitFile::RcInitFile()
72 _movieLibraryLimit(8),
76 // will be reset to something else if __OS2__x is defined:
77 _urlOpenerFormat("firefox -remote 'openurl(%u)'"),
79 DEFAULT_FLASH_PLATFORM_ID
" "\
80 DEFAULT_FLASH_MAJOR_VERSION
","\
81 DEFAULT_FLASH_MINOR_VERSION
","\
82 DEFAULT_FLASH_REV_NUMBER
",0"),
83 // An empty string leaves detection to VM.cpp:
85 _flashSystemManufacturer("Gnash "DEFAULT_FLASH_SYSTEM_OS
),
88 _verboseASCodingErrors(false),
89 _verboseMalformedSWF(false),
90 _verboseMalformedAMF(false),
92 _localdomainOnly(false),
93 _localhostOnly(false),
94 _log("gnash-dbg.log"),
98 _extensionsEnabled(false),
101 _streamsTimeout(DEFAULT_STREAMS_TIMEOUT
),
102 _solsandbox(DEFAULT_SOL_SAFEDIR
),
104 _sollocaldomain(false),
107 // TODO: give a default value, and let 0 mean "disabled" -- 0
108 // currently is overridden by libbase/shm.cpp
110 _ignoreFSCommand(true),
112 _saveStreamingMedia(false),
113 _saveLoadedMedia(false),
117 _microphoneDevice(-1),
118 _certfile("client.pem"),
119 _certdir("/etc/pki/tls"),
120 _rootcert("rootcert.pem"),
121 _ignoreShowMenu(true)
123 expandPath(_solsandbox
);
127 _urlOpenerFormat
= PrfQueryProfileString(HINI_USER
, (PSZ
)
128 "WPURLDEFAULTSETTINGS",
129 (PSZ
) "DefaultBrowserExe", NULL
,
130 (PVOID
) browserExe
, (LONG
)sizeof(browserExe
));
131 _urlOpenerFormat
+= " -remote 'openurl(%u)'";
134 // TODO: fetch GNASH_URLOPENER_FORMAT from the environment
137 RcInitFile::~RcInitFile()
141 // Look for a config file in the likely places.
143 RcInitFile::loadFiles()
145 // Note: This used to be bool but the return value was (a) never used
146 // and (b) only returned true if a gnashrc set by environment variable
147 // was successfully parsed. It seems we don't care whether a file
148 // actually exists or not anyway.
150 // Check the default system location
151 std::string loadfile
= SYSCONFDIR
;
153 #if !defined(__OS2__ ) && ! defined(__amigaos4__)
154 // On OS/2 only look in %HOME%
155 loadfile
.append("/gnashrc");
159 // Check the users home directory
160 const char *home
= 0;
161 #if defined (__amigaos4__)
162 //on AmigaOS we have a GNASH: assign that point to program dir
164 #elif defined(HAIKU_HOST)
166 if (B_OK
!= find_directory(B_USER_SETTINGS_DIRECTORY
, &bp
)) {
167 log_error(_("Failed to find user settings directory"));
173 home
= std::getenv("HOME");
178 loadfile
.append("/gnashrc");
180 loadfile
.append("/.gnashrc");
185 // Check the GNASHRC environment variable
186 // Parse each file only once
187 char *gnashrc
= std::getenv("GNASHRC");
189 std::string
paths(gnashrc
);
190 Tok
t(paths
, Sep(":"));
192 std::list
<std::string
> l
;
194 for (Tok::iterator i
= t
.begin(), e
= t
.end(); i
!= e
; ++i
) {
199 for (std::list
<std::string
>::const_iterator i
= l
.begin(), e
= l
.end(); i
!= e
; ++i
) {
206 RcInitFile::extractSetting(bool &var
, const std::string
&pattern
,
207 const std::string
&variable
, const std::string
&value
)
210 StringNoCaseEqual noCaseCompare
;
211 if ( noCaseCompare(variable
, pattern
) ) {
212 if ( noCaseCompare(value
, "on") || noCaseCompare(value
, "yes") ||
213 noCaseCompare(value
, "true")) {
216 if (noCaseCompare(value
, "off") || noCaseCompare(value
, "no") ||
217 noCaseCompare(value
, "false")) {
228 RcInitFile::parseList(PathList
&list
, const std::string
&action
,
229 const std::string
&items
)
232 if (action
== "set") {
233 // Clear array of hosts in previously parsed
237 StringNoCaseEqual noCaseCompare
;
239 if (noCaseCompare(items
, "off") || noCaseCompare(items
, "no") ||
240 noCaseCompare(items
, "false")) {
241 // Return empty array (allows disabling of global
242 // whitelists in favour of a blacklist)
247 Tok
t(items
, Sep(" "));
249 for (Tok::iterator i
= t
.begin(), e
= t
.end(); i
!= e
; ++i
)
257 RcInitFile::extractDouble(double& out
, const std::string
&pattern
,
258 const std::string
&variable
, const std::string
&value
)
261 StringNoCaseEqual noCaseCompare
;
263 if ( noCaseCompare(variable
, pattern
) ) {
264 std::istringstream
in(value
);
265 if (in
>> out
) return true;
267 // If the assignment fails, set the double to 0.
276 RcInitFile::expandPath (std::string
& path
)
279 // Leaves path unchanged on systems without
280 // POSIX tilde expansion.
283 //Don't build tilde expansion on systems without pwd.h
285 //Only if path starts with "~"
286 if (path
[0] == '~') {
288 // Initial "~" followed by "/"
289 if (path
.substr(1,1) == "/") {
291 const char *home
= std::getenv("HOME");
293 // if HOME set in env, replace ~ with HOME
294 path
.replace(0, 1, home
);
297 # ifdef HAVE_GETPWNAM //Don't try this on systems without getpwnam
299 // HOME not found in env: try using pwd
301 struct passwd
*password
= getpwuid(getuid());
302 const char *pwdhome
= password
->pw_dir
;
304 path
.replace(0, 1, pwdhome
);
306 //If all that fails, leave path alone
310 //Initial "~" is not followed by "/"
313 std::string::size_type firstslash
=
314 path
.find_first_of("/");
316 if (firstslash
!= std::string::npos
) {
317 // everything between initial ~ and /
318 user
= path
.substr(1, firstslash
- 1 );
320 else user
= path
.substr(1);
322 // find user using pwd
323 const char *userhome
= NULL
;
324 struct passwd
*password
= getpwnam(user
.c_str());
326 userhome
= password
->pw_dir
;
328 path
.replace(0, firstslash
, userhome
);
339 RcInitFile::writeList (const PathList
& list
, std::ostream
& o
)
341 for (PathList::const_iterator it
= list
.begin();
342 it
!= list
.end(); ++it
) {
348 // Parse the config file and set the variables.
350 RcInitFile::parseFile(const std::string
& filespec
)
355 std::string variable
;
360 StringNoCaseEqual noCaseCompare
;
362 if (filespec
.empty()) {
363 cerr
<< "RcInitFile::parseFile: empty filespec" << endl
;
367 if (stat(filespec
.c_str(), &stats
) != 0)
369 // This is a normal case, since we check many places for an RC file.
370 // So don't complain bitterly every time we run gnash!
371 // cerr << _("RcInitFile: couldn't open file: ") << filespec << endl;
375 in
.open(filespec
.c_str());
378 cerr
<< _("RcInitFile: couldn't open file: ") << filespec
<< endl
;
382 //cout << _("RcInitFile: parsing ") << filespec << endl;
384 // Read in each line and parse it
386 while (std::getline(in
, line
)) {
390 // Ignore comment and empty lines
391 if (line
.empty() || line
[0] == '#') {
395 std::istringstream
ss(line
);
397 // Get the first token
398 if (! (ss
>> action
)) {
403 // 'action' should never be empty, or (ss >> action)
404 // above would have failed
406 if ( action
[0] == '#' ) continue; // discard comments
409 if (! (ss
>> variable
)) {
410 // Do we need to warn here as well?
414 if (noCaseCompare(action
, "set") || noCaseCompare(action
, "append")) {
416 // The rest of the line is the value
417 if (!std::getline (ss
, value
)) {
418 cerr
<< boost::format(_("Warning: missing value for "
419 "variable \"%s\" in rcfile %s, line %d"))
420 % variable
% filespec
% lineno
<< endl
;
424 // Erase leading spaces.
425 // If there are nothing but spaces in the value,
426 // e.g. "set writelog ", value should be an empty string,
427 // so value.erase(0, string::npos) is correct.
428 value
.erase(0, value
.find_first_not_of(' '));
430 if (noCaseCompare(variable
, "urlOpenerFormat")) {
431 _urlOpenerFormat
= value
;
435 if (noCaseCompare(variable
, "flashVersionString")) {
436 _flashVersionString
= value
;
440 if(noCaseCompare(variable
, "GSTAudioSink")) {
441 _gstaudiosink
= value
;
445 if (noCaseCompare(variable
, "flashSystemOS")) {
446 _flashSystemOS
= value
;
450 if (noCaseCompare(variable
, "flashSystemManufacturer")) {
451 _flashSystemManufacturer
= value
;
455 if (noCaseCompare(variable
, "debuglog")) {
461 if (noCaseCompare(variable
, "mediaDir") ) {
463 _mediaCacheDir
= value
;
467 if (noCaseCompare(variable
, "documentroot") ) {
472 if (noCaseCompare(variable
, "blacklist") ) {
473 parseList(_blacklist
, action
, value
);
477 if (noCaseCompare(variable
, "whitelist")) {
478 parseList(_whitelist
, action
, value
);
482 if (noCaseCompare(variable
, "localSandboxPath")) {
483 parseList(_localSandboxPath
, action
, value
);
487 if (noCaseCompare(variable
, "SOLSafeDir")) {
493 if(noCaseCompare(variable
, "HWAccel")) {
498 if(noCaseCompare(variable
, "Renderer")) {
503 if(noCaseCompare(variable
, "MediaHandler")) {
504 _mediahandler
= value
;
508 if (noCaseCompare(variable
, "CertDir") ) {
514 if (noCaseCompare(variable
, "CertFile") ) {
520 if (noCaseCompare(variable
, "RootCert") ) {
525 if (noCaseCompare(action
, "set") ) {
526 extractSetting(_splashScreen
, "splashScreen", variable
,
529 extractSetting(_localhostOnly
, "localhost", variable
,
532 extractSetting(_localdomainOnly
, "localdomain", variable
,
535 extractSetting(_insecureSSL
, "insecureSSL", variable
,
538 extractSetting(_debugger
, "debugger", variable
, value
)
540 extractSetting(_actionDump
, "actionDump", variable
, value
)
542 extractSetting(_parserDump
, "parserDump", variable
, value
)
544 extractSetting(_writeLog
, "writelog", variable
, value
)
546 extractSetting(_popups
, "popupMessages", variable
, value
)
548 extractSetting(_sound
, "sound", variable
, value
)
550 extractSetting(_pluginSound
, "pluginsound", variable
, value
)
552 extractSetting(_verboseASCodingErrors
,
553 "ASCodingErrorsVerbosity", variable
, value
)
555 extractSetting(_verboseMalformedSWF
, "MalformedSWFVerbosity",
558 extractSetting(_verboseMalformedAMF
, "MalformedAMFVerbosity",
561 extractSetting(_extensionsEnabled
, "EnableExtensions",
564 extractSetting(_startStopped
, "StartStopped", variable
, value
)
566 extractSetting(_solreadonly
, "SOLReadOnly", variable
,
569 extractSetting(_sollocaldomain
, "solLocalDomain", variable
,
572 extractSetting(_lcdisabled
, "LocalConnection", variable
,
575 extractSetting(_lctrace
, "LCTrace", variable
,
578 extractNumber(_movieLibraryLimit
, "movieLibraryLimit",
581 extractNumber(_delay
, "delay", variable
, value
)
583 extractNumber(_verbosity
, "verbosity", variable
, value
)
585 extractNumber(_lcshmkey
, "LCShmkey", variable
, value
)
587 extractDouble(_streamsTimeout
, "streamsTimeout", variable
,
590 extractNumber(_quality
, "quality", variable
, value
)
592 extractSetting(_saveLoadedMedia
, "saveLoadedMedia",
595 extractSetting(_saveStreamingMedia
, "saveStreamingMedia",
598 extractSetting(_ignoreFSCommand
, "ignoreFsCommand", variable
,
601 extractNumber(_webcamDevice
, "webcamDevice", variable
,
604 extractNumber(_microphoneDevice
, "microphoneDevice", variable
, value
)
606 extractSetting(_ignoreShowMenu
, "ignoreShowMenu", variable
,
609 cerr
<< boost::format(_("Warning: unrecognized directive "
610 "\"%s\" in rcfile %s line %d"))
611 % variable
% filespec
% lineno
<< endl
;
613 } else if (noCaseCompare(action
, "include")) {
614 //cout << "Include directive in " << filespec << endl;
615 // TODO: resolve relative paths ?
616 // TODO: skip parsing if already parsed ?
617 // (would mess up user-requested parsing order, but
618 // would be safe in case of circular includes)
620 if (variable
.empty()) {
621 cerr
<< boost::format(_("Warning: empty include "
622 "specification in rcfile %s, line %d"))
623 % filespec
% lineno
<< endl
;
625 if ( variable
[0] != '/' ) {
626 cerr
<< boost::format(_("Warning: include specification "
627 "must be an absolute path in rcfile %s, "
628 "line %d")) % filespec
% lineno
<< endl
;
635 cerr
<< boost::format(_("Warning: unrecognized action \"%s\" in "
636 "rcfile %s, line %d")) % action
% filespec
% lineno
<< endl
;
648 RcInitFile::updateFile()
651 // We don't want to try writing to /etc/ et cetera, since
652 // these are likely to be system-wide defaults set by administrators
653 // or distros, useful for a model rcfile. They are likely to have
654 // no write permission anyway unless you are running Gnash with
655 // administrative privileges, and that is a bad idea.
657 std::string writefile
;
659 // The file specified in GNASHRC environment variable
660 // should be written first.
661 // If you name an important file in GNASHRC and 'save' the
662 // preferences, you'll obviously overwrite that file.
663 char *gnashrc
= std::getenv("GNASHRC");
665 std::string
filelist(gnashrc
);
667 if (filelist
.empty()) return false;
669 std::string::size_type pos
= filelist
.find_last_of(':');
671 if (pos
== std::string::npos
) {
672 // no separator: just one file.
673 writefile
= filelist
;
675 writefile
= filelist
.substr(pos
+ 1);
678 // Check the users home directory
679 const char *home
= NULL
;
680 #if defined(__amigaos4__)
681 //on AmigaOS we have a GNASH: assign that point to program dir
683 #elif defined(HAIKU_HOST)
685 if (B_OK
!= find_directory(B_USER_SETTINGS_DIRECTORY
, &bp
)) {
686 log_error(_("Failed to find user settings directory"));
692 home
= std::getenv("HOME");
697 writefile
.append("/gnashrc");
699 writefile
.append("/.gnashrc");
704 if (writefile
.empty()) {
708 return updateFile(writefile
);
713 // Write the changed settings to the config file
715 RcInitFile::updateFile(const std::string
& filespec
)
718 if (filespec
.empty()) {
724 out
.open(filespec
.c_str());
727 cerr
<< boost::format(_("Couldn't open file %s for writing")) % filespec
<< endl
;
731 const std::string cmd
= "set ";
733 // Bools and numbers. We want boolean values written as words, hex values
734 // prefixed with '0x'.
735 out
<< std::boolalpha
<< std::showbase
<<
736 _("# Generated by Gnash. Manual changes to this file may be overridden.")
738 cmd
<< "splashScreen " << _splashScreen
<< endl
<<
739 cmd
<< "localHost " << _localhostOnly
<< endl
<<
740 cmd
<< "localDomain " << _localdomainOnly
<< endl
<<
741 cmd
<< "insecureSSL " << _insecureSSL
<< endl
<<
742 cmd
<< "debugger " << _debugger
<< endl
<<
743 cmd
<< "actionDump " << _actionDump
<< endl
<<
744 cmd
<< "parserDump " << _parserDump
<< endl
<<
745 cmd
<< "writeLog " << _writeLog
<< endl
<<
746 cmd
<< "sound " << _sound
<< endl
<<
747 cmd
<< "popupMessages " << _popups
<< endl
<<
748 cmd
<< "pluginSound " << _pluginSound
<< endl
<<
749 cmd
<< "ASCodingErrorsVerbosity " << _verboseASCodingErrors
<< endl
<<
750 cmd
<< "malformedSWFVerbosity " << _verboseMalformedSWF
<< endl
<<
751 cmd
<< "malformedAMFVerbosity " << _verboseMalformedAMF
<< endl
<<
752 cmd
<< "enableExtensions " << _extensionsEnabled
<< endl
<<
753 cmd
<< "startStopped " << _startStopped
<< endl
<<
754 cmd
<< "streamsTimeout " << _streamsTimeout
<< endl
<<
755 cmd
<< "movieLibraryLimit " << _movieLibraryLimit
<< endl
<<
756 cmd
<< "quality " << _quality
<< endl
<<
757 cmd
<< "delay " << _delay
<< endl
<<
758 cmd
<< "verbosity " << _verbosity
<< endl
<<
759 cmd
<< "solReadOnly " << _solreadonly
<< endl
<<
760 cmd
<< "solLocalDomain " << _sollocaldomain
<< endl
<<
761 cmd
<< "SOLSafeDir " << _solsandbox
<< endl
<<
762 cmd
<< "localConnection " << _lcdisabled
<< endl
<<
763 cmd
<< "LCTrace " << _lctrace
<< endl
<<
764 cmd
<< "LCShmkey " << std::hex
<< (boost::uint32_t) _lcshmkey
<< endl
<<
765 cmd
<< "ignoreFSCommand " << _ignoreFSCommand
<< endl
<<
766 cmd
<< "ignoreShowMenu " << _ignoreShowMenu
<< endl
<<
767 cmd
<< "saveStreamingMedia " << _saveStreamingMedia
<< endl
<<
768 cmd
<< "saveLoadedMedia " << _saveLoadedMedia
<< endl
<<
772 // If a string is empty, Gnash defaults to the values set in the
775 // This might be irritating for users who, for instance, set
776 // debuglog to nothing, only to find it returns to "gnash-debug.log"
777 // at the next run (even though that's not the way to use it...)
779 cmd
<< "mediaDir " << _mediaCacheDir
<< endl
<<
780 cmd
<< "debuglog " << _log
<< endl
<<
781 cmd
<< "documentroot " << _wwwroot
<< endl
<<
782 cmd
<< "flashSystemOS " << _flashSystemOS
<< endl
<<
783 cmd
<< "flashVersionString " << _flashVersionString
<< endl
<<
784 cmd
<< "urlOpenerFormat " << _urlOpenerFormat
<< endl
<<
785 cmd
<< "GSTAudioSink " << _gstaudiosink
<< endl
;
787 // Lists. These can't be handled very well at the moment. The main
788 // inconvenience would be that disabling a list makes it an empty
789 // array in the rc class, and writing that to a file would lose that
790 // blacklist you'd spent ages collecting.
792 // For now we'll just make sure lists that gnashrc finds are written.
793 // Commented out lists in gnashrc will be deleted!
795 // The difference between append and set also can't be used without
796 // a bit of trickery. It would be possible, for instance, to pass a
797 // special character (e.g. '+') as the first element of an array from
798 // the gui. However, this is possibly not all that useful anyway,
799 // as lists in other parsed rcfiles would be taken over and written
800 // as part of the new file.
802 // It might be necessary to have a 'useWhitelist' flag as well
803 // as a whitelist. This would allow rcfile to keep a whitelist and write
804 // it to disk, but not have to use it.
806 out
<< cmd
<< "whitelist ";
807 writeList (_whitelist
, out
);
809 out
<< cmd
<< "blacklist ";
810 writeList (_blacklist
, out
);
812 // This also adds the base URL of the current SWF, as that gets
813 // added to the path automatically...
814 //out << cmd << "localSandboxPath ";
815 //writeList (_localSandboxPath, out);
823 RcInitFile::useSplashScreen(bool value
)
825 _splashScreen
= value
;
829 RcInitFile::useLocalDomain(bool value
)
831 _localdomainOnly
= value
;
835 RcInitFile::useLocalHost(bool value
)
837 _localhostOnly
= value
;
841 RcInitFile::useActionDump(bool value
)
847 RcInitFile::showASCodingErrors(bool value
)
849 _verboseASCodingErrors
= value
;
853 RcInitFile::showMalformedSWFErrors(bool value
)
855 _verboseMalformedSWF
= value
;
859 RcInitFile::useParserDump(bool value
)
865 RcInitFile::useWriteLog(bool value
)
874 cerr
<< endl
<< "Dump RcInitFile:" << endl
;
875 cerr
<< "\tTimer interupt delay value: " << _delay
<< endl
;
876 cerr
<< "\tFlash debugger: "
877 << ((_debugger
)?"enabled":"disabled") << endl
;
878 cerr
<< "\tVerbosity Level: " << _verbosity
<< endl
;
879 cerr
<< "\tDump ActionScript processing: "
880 << ((_actionDump
)?"enabled":"disabled") << endl
;
881 cerr
<< "\tDump parser info: "
882 << ((_parserDump
)?"enabled":"disabled") << endl
;
883 cerr
<< "\tActionScript coding errors verbosity: "
884 << ((_verboseASCodingErrors
)?"enabled":"disabled") << endl
;
885 cerr
<< "\tMalformed SWF verbosity: "
886 << ((_verboseASCodingErrors
)?"enabled":"disabled") << endl
;
887 cerr
<< "\tUse Splash Screen: "
888 << ((_splashScreen
)?"enabled":"disabled") << endl
;
889 cerr
<< "\tUse Local Domain Only: "
890 << ((_localdomainOnly
)?"enabled":"disabled") << endl
;
891 cerr
<< "\tUse Localhost Only: "
892 << ((_localhostOnly
)?"enabled":"disabled") << endl
;
893 cerr
<< "\tWrite Debug Log To Disk: "
894 << ((_writeLog
)?"enabled":"disabled") << endl
;
895 cerr
<< "\tAllow insecure SSL connections: "
896 << ((_insecureSSL
)?"yes":"no") << endl
;
897 cerr
<< "\tEnable sound: "
898 << ((_sound
)?"enabled":"disabled") << endl
;
899 cerr
<< "\tEnable Plugin sound: "
900 << ((_pluginSound
)?"enabled":"disabled") << endl
;
901 cerr
<< "\tEnable Extensions: "
902 << ((_extensionsEnabled
)?"enabled":"disabled") << endl
;
905 cerr
<< "\tDebug Log name is: " << _log
<< endl
;
908 if (!_flashVersionString
.empty()) {
909 cerr
<< "\tFlash Version String is: " << _flashVersionString
<< endl
;
912 if(!_gstaudiosink
.empty()) {
913 cerr
<< "\tGST Audio Sink is: " << _gstaudiosink
<< endl
;
916 cerr
<< "\tWhitelist: ";
917 writeList (_whitelist
, cerr
);
919 cerr
<< "\tBlacklist: ";
920 writeList (_blacklist
, cerr
);
922 cerr
<< "\tSandbox: ";
923 writeList (_localSandboxPath
, cerr
);
927 } // end of namespace gnash
931 // indent-tabs-mode: t