using System; using System.IO; using System.Collections; using System.Collections.Generic; using System.Text.RegularExpressions; namespace bytex64.WebThing { public struct SearchHandlerPair { public string Shortcut; public string Plugin; public SearchHandlerPair(string s, string p) { Shortcut = s; Plugin = p; } } public class Config { public static List ConfigPath; public static string ConfigPathOut = null; public static List PluginPath; public static Dictionary Options; public static Dictionary> PluginOptions; public static string[] Arguments; public static List Plugins; public static List SearchHandlers; public static string DefaultSearchHandler; private static HashSet CommandLineOptions; private static Regex item_re = new Regex(@"^(?:([\w.]+)\.)?(\w+)$"); private static Regex file_var_re = new Regex(@"^([\w.]+)\s*=\s*(.*)$"); private static Regex file_command_re = new Regex(@"^([\w]+)\s*(.*)$"); static Config() { Options = new Dictionary(); PluginOptions = new Dictionary>(); CommandLineOptions = new HashSet(); Plugins = new List(); SearchHandlers = new List(); // Set up ConfigPath IDictionary Env = Environment.GetEnvironmentVariables(); ConfigPath = new List(); ConfigPath.Add("/etc/WebThing"); if (Env.Contains("HOME")) { string homepath = Env["HOME"] + "/.config/WebThing"; ConfigPath.Add(homepath); if (Directory.Exists(homepath)) ConfigPathOut = homepath; } string LocalAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); if (LocalAppData != "") { string homepath = LocalAppData + "/WebThing"; ConfigPath.Add(homepath); if (Directory.Exists(homepath)) ConfigPathOut = homepath; } // Set up PluginPath PluginPath = new List(); PluginPath.Add(Environment.GetEnvironmentVariable("WEBTHING_HOME") + "/plugins"); PluginPath.Add(Environment.GetEnvironmentVariable("WEBTHING_HOME") + "/searchplugins"); } private static void ParseOption(string key, string val) { Match m = item_re.Match(key); string plugin = m.Groups[1].Value; string name = m.Groups[2].Value; if (plugin.Length > 0) { // Plugin Option if (!PluginOptions.ContainsKey(plugin)) PluginOptions[plugin] = new Dictionary(); PluginOptions[plugin][name] = val; } else { // Global Option switch(key.ToLower()) { case "plugin": Plugins.Add(val); break; default: Options[key] = val; break; } } } public static void DumpOptions() { Console.WriteLine("Options:"); foreach (string key in Options.Keys) Console.WriteLine(" {0}\t{1}", key, Options[key]); Console.WriteLine("Plugin Options:"); foreach (string plugin in PluginOptions.Keys) { Console.WriteLine(" {0}", plugin); foreach (string key in PluginOptions[plugin].Keys) Console.WriteLine(" {0}\t{1}", key, PluginOptions[plugin][key]); } Console.WriteLine("Arguments: {0}", String.Join(" ", Arguments)); } public static void ParseCommandLine() { Queue q = new Queue(); foreach (string s in System.Environment.GetCommandLineArgs()) { q.Enqueue(s); } q.Dequeue(); // Remove self argument Regex SimpleOpt = new Regex(@"^-([\w.]+)(?:[:=](.*))?$"); Regex LongOpt = new Regex(@"^--([\w.]+)$"); List args = new List(); while (q.Count > 0) { string opt = q.Dequeue(); Match m; m = SimpleOpt.Match(opt); if (m.Success) { string key = m.Groups[1].Value; string val = m.Groups[2].Value; if (val.Length > 0) { ParseOption(key, val); } else { ParseOption(key, null); } CommandLineOptions.Add(key); continue; } m = LongOpt.Match(opt); if (m.Success) { string key = m.Groups[1].Value; if (q.Count > 0) { string val = q.Peek(); if (!(SimpleOpt.IsMatch(val) || LongOpt.IsMatch(val))) { q.Dequeue(); ParseOption(key, val); } else { ParseOption(key, null); } } else { ParseOption(key, null); } CommandLineOptions.Add(key); continue; } // else args.Add(opt); } Arguments = args.ToArray(); } public static void Load() { foreach (string path in ConfigPath) { if (!Directory.Exists(path)) continue; string[] ConfigFiles = Directory.GetFiles(path, "*.conf"); foreach (string file in ConfigFiles) { LoadFile(file); } } if (Options.ContainsKey("config")) LoadFile(Options["config"]); } public static void LoadFile(string filename) { TextReader f; try { f = new StreamReader(filename); } catch (FileNotFoundException) { Console.WriteLine("Could not open configuration file {0}", filename); return; } string line; while ((line = f.ReadLine()) != null) { Match m; line = line.Trim(); m = file_var_re.Match(line); if (m.Success) { string key = m.Groups[1].Value; if (!CommandLineOptions.Contains(key)) ParseOption(key, m.Groups[2].Value); continue; } m = file_command_re.Match(line); if (m.Success) { string cmd = m.Groups[1].Value.ToLower(); switch(cmd) { case "plugin": Plugins.Add(m.Groups[2].Value); break; case "searchhandler": string[] args = Regex.Split(m.Groups[2].Value, @"\s+"); if (args.Length != 2) { Console.WriteLine("Expecting two arguments for SearchHandler."); break; } SearchHandlers.Add(new SearchHandlerPair(args[0], args[1])); break; case "defaultsearchhandler": DefaultSearchHandler = m.Groups[2].Value; break; default: Console.WriteLine("Unknown Command in {0}: {1}", filename, line); break; } continue; } } f.Close(); } public static void SaveFile(string filename) { TextWriter f; try { f = new StreamWriter(filename); } catch (IOException) { Console.WriteLine("Could not save configuration to {0}", filename); return; } foreach (string key in Options.Keys) { if (CommandLineOptions.Contains(key)) continue; f.WriteLine("{0} = {1}", key, Options[key]); } foreach (string plugin in PluginOptions.Keys) { foreach (string key in PluginOptions[plugin].Keys) { string pkey = String.Format("{0}.{1}", plugin, key); if (CommandLineOptions.Contains(pkey)) continue; f.WriteLine("{0} = {1}", pkey, PluginOptions[plugin][key]); } } f.Close(); } public static void SaveFile(WebThingPlugin p, string filename) { string plugin_name = p.GetType().FullName; SaveFile(plugin_name, filename); } public static void SaveFile(string plugin_name, string filename) { // TODO: Throw exception if plugin does not exist TextWriter f = new StreamWriter(filename); foreach (string key in PluginOptions[plugin_name].Keys) { f.WriteLine("{0}.{1} = {2}", plugin_name, key, PluginOptions[plugin_name][key]); } f.Close(); } // Data parsers public static bool ParseBool(string v) { switch(v.ToLower()) { case "true": case "t": case "1": case "on": case "yes": return true; } return false; } } }