741d4ba298559f4b4257a266a46713fd2410cadb
[atutor.git] / mods / wiki / tools / setup
1 #!/usr/local/bin/php -qC
2 <?php
3 /*
4    Console/terminal tool to generate ewiki.ini, config.php or a
5    monsterwiki file (plugins+core merged into single php script).
6    Works best on Linux flavours, with dialog/cdialog/whiptail or
7    Xdialog/gdialog/kdialog installed.
8
9    - $set contains list of plugin names
10    - constants and values are added to $set only after the according
11      plugin gets activated
12    - menus switch to each other by name, but some are implemented by
13      callback functions ("OPTIONS" is regenerated on the fly)
14 */
15
16 // $_ENV["NO_X"] = 1;
17 // $_ENV["DIALOG"] = "cdialog";
18 define("OPTIONS_SPACING", 0);
19
20
21 #-- init
22 chdir(dirname(dirname(__FILE__)));  // change into ewiki base directory
23 include_once("plugins/lib/upgrade.php");  // PHP4.3 minimum
24 dialog::init();   // prepare UI
25 include_once("plugins/lib/pluginmetadata.php");
26
27 #-- read in *.meta files
28 ewiki_pmd(0,1,0,"d_gauge"); d_gauge();
29
30
31 #-- plugin/option states
32 $set_init = array(
33    ".\$ini" => "ewiki.ini",
34    ".\$php" => "config.php",
35    ".\$mwiki" => "monsterwiki.php",
36    "DB_INIT" => "mysql_connect(localhost,user,password) && mysql_query(dbname)",
37    "EWIKI_DB_TABLE_NAME" => "ewiki",
38    "EWIKI_DB_UTF8" => 0,
39    "EWIKI_DB_BIN64" => 0,
40    "EWIKI_DBFILES_DIRECTORY" => "./files/",
41    "EWIKI_DBFILES_GZLEVEL" => 0,
42    "EWIKI_DB_FAST_FILES" => 0,
43    "EWIKI_DBFF_ACCURATE" => 0,
44    "DZF2_HIT_COUNTING" => 1,
45    "EWIKI_DBA" => "/tmp/mywiki.flatfile",
46 );
47 $set = $set_init;
48 $priority_1 = "core,required,standard,default,important";
49 m_reset();     // initial settings
50 m_load_dat();  // load backup values
51
52
53 #-- menus ----------------------------------------------------------------
54 $menus = array(
55    "MAIN" => array(
56       array("PLUGINS", "Select plugins", "List available extension plugins to enable or disable them.", ""),
57       array("OPTIONS", "Tweak configuration options and plugin settings", "Override and pre-define constants and configuration variables.", "m_options"),
58       array("DATABASE", "Choose and configure database backend", "Unlike the backend selection under plugins, this entry is for auto-initialization.", "m_database"),
59       array("SAVE_PHP", "Generate \"config.php\"", "Exports a ready-to-use ewiki config include script.", "m_save_php"),
60       array("SAVE_INI", "Generate \"ewiki.ini\"", "An .ini file can contain all plugin and configuration options.", "m_save_ini"),
61       array("SAVE_WIKI", "Generate \"monsterwiki.php\" script", "All plugins and settings get merged into one script.", "m_save_mwiki"),
62       array("LOAD_PHP", "Decipher settings from \"config.php\"", "Reading from .php scripts is not reliable.", "m_load_php"),
63       array("LOAD_INI", "Load settings from \"ewiki.ini\"", "Save settings into an reusable .ini-style configuration file.", "m_load_ini"),
64       array("DONE", "Exit this tool", "Automatically saves current plugin and config settings. Press ^C else.", "m_exit"),
65       array("HELP", "Documentation", "Additional usage informations for this utility.", "m_help"),
66 /*    array("IDENTIFIER",                 // denotes next/sub menu
67  *          "Title", "Help text",         // for display
68  *          "func_handler(arg2)",         // entry handler, if no sub menu
69  *          "func_mangle_display_menu",   // callback, tweaks title with $set values   */
70    ),
71    "OPTIONS" => array(
72       // automatically emptied sub menu, so the menu() selection ignores it
73    ),
74    "PLUGINS" => array(
75       array("PLUGINLIST", "All plugins in one list", "Gives complete overview over available plugins, alphabetical but rough listing.", "m_checklist_plugins()"),
76       array("FAVORITES", "Enable plugins by priority / favorites", "Selects multiple plugins/features at once.", ""),
77    ),
78    "FAVORITES" => array(
79       array("PR_core", "priority: core - plugins that must be loaded", "Core and required plugins.", "m_enable_by_priority(core,required)"),
80       array("PR_standard", "add standard plugins - loaded in default setup", "", "m_enable_by_priority(core,required,standard,default)"),
81       array("PR_important", "add important plugins - highly recommended", "", "m_enable_by_priority(important)"),
82       array("PR_recommended", "add recommended plugins", "", "m_enable_by_priority(recommended)"),
83       array("PR_optional", "add optional plugins", "", "m_enable_by_priority(optional)"),
84       array("PR_extra", "add extra plugins", "", "m_enable_by_priority(extra)"),
85       array("RESET", "Reset plugin list and options (to standard)", "All core plugins will be selected.", "m_reset"),
86       array("FAV_mario", "personal favorites of: Mario", "http,rss,qdiff,mpi,flat_files,textupload,limit_links,rc,wikinews,...", "m_enable_list(fix,http,http_cache,xml,feed,feedparse,raw,diff,rss,like_pages,htm,info_qdiff,email_protect,jump,notify,fancy_list_dict,flat_files,imgresize_gd,search_highlight,editable,xmlrpc,opensearch,linkdatabase,css,,definitionlinks,mpi,mpi_backtree,mpi_embed,mpi_insert,mpi_survey,mpi_syndicate,mpi_backlinks,mpi_localsitemap,mpi_tableeditor,mpi_addlink,aboutplugins,powersearch,textupload,wikinews,recentchanges,authorname,limitlinks,ewiki)"),
87    ),
88    "DATABASE" => array(
89       array("DB_PLUGIN", "Choose database backend", "Only one generic plugin/backend should be chosen.", "m_checklist_plugins(database)"),
90       array("DB_INIT", "Define how to initialize database / connect to it", "Initialization is mostly necessary for SQL databases only.", "m_set_option2(Set the SQL/DBA database initialization using its generic initialization function call, but that the syntax is restricted here - absolutely NO spaces and quotation marks around the arguments. For MySQL you`d use mysql_connect(, for PgSql you say anydb_connect( or pg_connect( and for Berkely/Sleepycat DBA files you set this to dba_open( instead."),
91       array("DB_OPTIONS", "Set other parameters for your database plugin", "Unsorted list, not all constants/settings apply to all database types.", ""),
92    ),
93    "DB_OPTIONS" => array(
94       array("EWIKI_DB_TABLE_NAME", "SQL table name (ewiki)", "[sql] database table name", "m_set_option(mysql)"),
95       array("EWIKI_DB_UTF8", "Code UTF-8 from/to database (Postgres)", "[pgsql] unicode2latin", "m_set_option(anydb)"),
96       array("EWIKI_DB_BIN64", "Encipher binary entries in the database (Postgres)", "[pgsql] binary as base64 encoded TEXT columns", "m_set_option(anydb)"),
97       array("EWIKI_DBFILES_DIRECTORY", "where to store flat files (./files/)", "[flat_files] storage directory", "m_set_option(flat_files)"),
98       array("EWIKI_DB_FAST_FILES", "fast file format, php serializiation (0)", "[flat_files] use `application/vnd.php.serialized` format", "m_set_option(flat_files)"),
99       array("EWIKI_DBFILES_GZLEVEL", "compress flat files (0)", "[flat_files] compression", "m_set_option(flat_files)"),
100       array("EWIKI_DBFF_ACCURATE", "more correct return values {slower} for some functions  (dzf2)", "[flat_files/dzf2] correctness vs. speed", "m_set_option(dzf2)"),
101       array("DZF2_HIT_COUNTING", "count page acccess (dzf2)", "[flat_files/dzf2] hits", "m_set_option(dzf2)"),
102       array("EWIKI_DBA", "Berkely/Sleepycat DBA storage file", "[dba] filename", "m_set_option(dba)"),
103    ),
104 );
105 #-- append plugin list menus
106 foreach (ewiki_pmd_by_category() as $cat=>$ls) {
107    $menus["PLUGINS"][] = array("$cat/", "category $cat", "", "m_checklist_plugins($cat)");
108 }
109
110
111
112 #-- main loop ------------------------------------------------------------
113 $menu="MAIN";
114 do {
115    menu();
116 }
117 while (true);
118
119 #-- display and switch between menus, call menu functions, dialog interface
120 function menu($GOTO="", $BACK="MAIN")
121 {
122    global $menus, $menu, $dialog_exit;
123    static $menu_stack = array();
124
125    #-- display
126    $next = dialog::menu($menus[$menu], "ewiki setup/config tool", "$menu menu");
127
128    #-- see what to do
129    if ($menus[$next]) {
130       array_push($menu_stack, $menu);
131       $menu = $next;
132    }
133    elseif ($dialog_exit=="1") {
134       $menu = array_pop($menu_stack);
135       if (!$menu || !$menus[$menu]) {
136          $menu = $BACK;
137       }
138    }
139    else {
140       #-- search selected entry
141       foreach ($menus[$menu] as $l)  {
142          if ($l[0] == $next) {
143             $selected = $l;
144          }
145       }
146       #-- call
147       if ($selected) {
148          m_call_func($selected[3], $next);
149       }
150    }
151 }
152
153
154
155
156 #== control code ($set plugins) ==========================================
157
158
159 #-- enable/disable single plugin
160 function m_switch_plugin($id, $id2) {
161    global $set;
162    if ($set[$id]) {
163       $set[$id] = false;
164    }
165    else {
166       $set[$id] = true;
167    }
168 }
169
170
171 #-- set plugin state from (inclusion) priority class
172 function m_reset()
173 {
174    global $set, $ewiki_pmd, $priority_1;
175    foreach ($ewiki_pmd as $id=>$row) {
176       $set[$id] = false;
177    }
178    m_enable_by_priority("", $priority_1);
179 }
180
181
182 #-- set plugins from comma separated priority list
183 function m_enable_by_priority($next, $priority)
184 {
185    global $set, $ewiki_pmd;
186    $priority = ",,,$priority,";
187    foreach ($ewiki_pmd as $id=>$row) {
188       if (strpos($priority, ",$row[priority],")) {
189          $set[$id] = true;
190       }
191    }
192 }
193
194
195 #-- enable plugins by name (favorite lists)
196 function m_enable_list($next, $list)
197 {
198    global $set, $ewiki_pmd;
199    foreach (explode(",", $list) as $id) {
200       $set[trim($id)] = true;
201    }
202 }
203
204
205 #-- load setup.dat from last session
206 function m_load_dat() {
207    if ($dat = file_get_contents("tools/setup.dat")) {
208       $GLOBALS["set"] = unserialize($dat);
209    }
210 }
211
212
213 #-- handles function calls in menus
214 function m_call_func($funcdef, $arg1) {
215    $func = strtok($funcdef, "(");
216    $args = array($arg1, strtok(")"));
217    call_user_func_array($func, $args);
218 }
219
220
221 #-- callback function, which mangles the displayed title for
222 #   menu entries in the plugin section (injects values from $set[])
223 function m_inj_menu_set(&$title, $row) {
224    global $set;
225    $id = $row[0];
226    if (isset($set[$id])) {
227       $title = str_pad($title, 30, " ")
228              . " " . ($set[$id]? "[YES]":"[NO]");
229    }
230 }
231
232
233 #-- show checkboxes to enable plugins from a category
234 function m_checklist_plugins($next, $cat) {
235    global $set, $ewiki_pmd;
236    $list = array();
237    foreach (ewiki_pmd_by_category() as $c=>$ls) {
238       if (!$cat || ($cat==$c)) {
239          foreach ($ls as $id=>$row) if (!ewiki_pmd_hidden($row)) {
240             $list[$id] = array($id, $row["title"], $row["description"]);
241          }
242       }
243    }
244    ksort($list);
245    dialog::check($list, $set, "ewiki setup/config tool", "enable or disable $cat plugins");
246 }
247
248
249 #-- help screen for plugins
250 function m_plugin_info($id) {
251    global $ewiki_pmd;
252    if (!$ewiki_pmd[$id]) {
253       $id = preg_replace("/[^\w\d]/", "", $id);
254       foreach ($ewiki_pmd as $i=>$row) {
255          if ($id == preg_replace("/[^\w\d]/", "", $row["description"])) {
256             $id = $i;
257             break;
258          }
259       }
260    }
261    if ($row = $ewiki_pmd[$id]) {
262       $text = "id: $id\n";
263       foreach ($row as $i=>$v) {
264          $text .= "$i: $v\n";
265       }
266       $text = strtr($text, "'", "`");
267       dialog::real("--title '$id' --msgbox '$text' 18 70");
268    }
269 }
270
271
272
273
274 #== $set options =========================================================
275
276
277 #-- dynamic sub-menu
278 function m_options() {
279    global $menu, $menus, $opts_l;
280    global $set, $ewiki_pmd;
281
282    #-- hack, calls main menu() function for display
283    $menu = "OPTIONS";
284    do {
285
286       #-- regenerate menu (in case something changed)
287       $opts_l = get_option_list();
288       $menus["OPTIONS"] = array();
289       foreach ($opts_l as $row) {
290          list($name, $val, $help, $id, $default) = $row;
291          if (OPTIONS_SPACING && ($id != $last_id)) {
292             $menus["OPTIONS"][] = array(" [$id]", "", "", "");
293             $last_id = $id;
294          }
295          $menus["OPTIONS"][] = array($name, "$val", "[$id] $help (default=$default)", "m_set_option($id)");
296       }
297
298       menu();
299    } while (($menu != "MAIN")
300          && ($menus["OPTIONS"]));
301    $menus["OPTIONS"] = array();
302 }
303
304
305 #-- settings from all enabled and auto plugins
306 function get_option_list() {
307    $ls = array();
308    foreach (final_plugin_list() as $id) {
309       foreach (get_config_options($id) as $row) {
310          $ls[$row[0]] = $row;
311       }
312    }
313    return($ls);
314 }
315 function get_config_options($id) {
316    global $ewiki_pmd, $set;
317    $r = array();
318    foreach (explode("\n", $ewiki_pmd[$id]["config"]) as $line) {
319       if (preg_match("#^(.+?)=(.*?)(?:\s//(.+))?$#", trim($line), $uu)) {
320          $name = trim($uu[1]);
321          $value = trim($uu[2]);
322          $value = preg_replace("#^(\d)\|\d$#", "$1", $value);   // for "0|1"
323          $value = preg_replace("#^\"([^\d].*)\"$#", "$1", $value);
324          $help = trim($uu[3]);
325          if (!isset($set[$name])) {
326             $set[$name] = $value;       // set default config value
327          }
328          $r[] = array($name, $set[$name], $help, $id, $value);
329       }
330    }
331    return($r);
332 }
333
334
335 #-- edit config setting
336 function m_set_option($name, $id) {
337    global $set, $opts_l;
338    dialog::edit("$name", $set[$name], "Change configuration option/constant", "This setting is defined/used by the `$id` plugin.\n\n" . $opts_l[$name][2] . "\n\n");
339 }
340
341 #-- help from 2nd parameter (instead of $opts_l)
342 function m_set_option2($name, $help) {
343    global $set;
344    dialog::edit("$name", $set[$name], "Set option", $help);
345 }
346
347
348
349
350
351 #-- safe+load code -------------------------------------------------------
352
353
354 #-- save ewiki.ini
355 function m_save_ini() {
356    global $set, $dialog_exit;
357    dialog::edit(".\$ini", $set[".\$ini"], "Save configuration as ewiki.ini file", "Give the filename under which to save the current settings. Beware, that any existing file will be overwritten.");
358    if ($dialog_exit) { return; }
359    file_put_contents($set[".\$ini"], m_mk_ini());
360 }
361
362
363 #-- generate ewiki.ini
364 function m_mk_ini() {
365    global $set, $ewiki_pmd;
366
367    #-- start ewiki.ini
368    $T = "; automatically generated configuration summary\n; see ewiki config wizard\n";
369    $T .= "\n[db]\n";
370    if ($set["DB_INIT"]) {
371       $T .= "init = ".$set["DB_INIT"]."\n";
372    }
373    else {
374       $T .= "; no initialization necessary, or no database backend specified\n";
375    }
376
377    #-- config
378    $T .= "\n[settings]\n";
379    foreach (get_option_list() as $row) {
380       $T .= "$row[0] = $row[1]\n";
381    }
382
383    #-- plugins
384    $T .= "\n[plugins]\n";
385    foreach (final_plugin_list() as $id) {
386       if ($fn = $ewiki_pmd[$id]["fn"]) {
387          $T .= "load = $fn\n";
388       }
389       else {
390          $T .= ";load = $id\n";
391       }
392    }
393    return($T . "\n");
394 }
395
396
397 #-- save config.php
398 function m_save_php() {
399    global $set, $dialog_exit;
400    dialog::edit(".\$php", $set[".\$php"], "Save configuration as config.php file", "To which filename do you wish the configuration script to be written? This will overwrite any existing file.");
401    if ($dialog_exit) { return; }
402    file_put_contents($set[".\$php"], m_mk_php());
403 }
404
405
406 #-- generate config.php body
407 function m_mk_php($with_plugins=1) {
408    global $set, $ewiki_pmd;
409
410    #-- start config.php
411    $T = "<?php\n# automatically generated configuration file\n# see ewiki config/setup wizard\n";
412    $T .= "\n#-- db\n";
413    if ($set["DB_INIT"]) {
414       foreach (split("&&|;", $set["DB_INIT"]) as $str) {
415          $fn = strtok(trim($str), "(");
416          $args = explode(",", strtok(")"));
417          $args = '"' . implode('", "', $args) . '"';
418          $fn = trim(strtok($fn, "/"));
419          $T .=  "if (function_exists(\"$fn\")) {\n   $fn($args);\n}\n";
420       }
421    }
422    else {
423       $T .= "// no initialization necessary, or no database backend configured\n";
424    }
425
426    #-- config
427    $T .= "\n#-- settings\n";
428    foreach (get_option_list() as $row) {
429       list($name, $val) = $row;
430       if (!preg_match("/^\d+$/", $val)) {
431          $val = "\"" . $val . "\"";
432       }
433       if ($name[0] == "$") {
434          $T .= "$name = $val;\n";
435       }
436       else {
437          $T .= "define(\"$name\", $val);\n";
438       }
439    }
440
441    #-- plugins
442    if ($with_plugins) {
443       $T .= "\n#-- plugins\n";
444       foreach (final_plugin_list() as $id) {
445          if ($fn = $ewiki_pmd[$id]["fn"]) {
446             $T .= "include_once(\"$fn\");\n";
447          }
448          else {
449             $T .= "//plugin not found: $id\n";
450          }
451       }
452    }
453    return($T . "\n?" . ">");
454 }
455
456
457 #-- save config.php
458 function m_save_mwiki() {
459    global $set, $ewiki_pmd, $dialog_exit;
460    dialog::edit(".\$mwiki", $set[".\$mwiki"], "Export a MonsterWiki", "Merge all plugins and configuration data into one giant PHP script.");
461    if ($dialog_exit) { return; }
462
463    #-- merge everything together
464    $f = fopen($mwiki=$set[".\$mwiki"], "wb");
465    fwrite($f, m_mk_php($_with_plugins=0));
466    $list = final_plugin_list();
467    foreach ($list as $n=>$id) {
468       if (file_exists($fn = $ewiki_pmd[$id]["fn"])) {
469          fwrite($f, file_get_contents($fn));
470       }
471       d_gauge($n, count($list), "assembling $mwiki", 75000, 2);
472    }
473    fclose($f);
474    d_gauge(0,0);
475 }
476
477
478 #-- add dependencies to $set array, send list
479 function final_plugin_list($add_required=1) {
480    global $set, $ewiki_pmd;
481    if ($add_required) {
482       m_enable_by_priority(".FINALIZE", "core,required");
483    }
484    $list = array();
485    foreach ($set as $id=>$state) {
486       if ($id && $state && $ewiki_pmd[$id]) {
487          $list[] = $id;
488       }
489    }
490    ewiki_pmd_resolve_dependencies($list, $_add_suggested=0);
491    return($list);
492 }
493
494
495
496
497 #== loading ==============================================================
498
499
500 #-- load from ewiki.ini file (without [para] dissection)
501 function m_load_ini() {
502    global $set, $set_init, $dialog_exit, $ewiki_pmd;
503    $pmd_by_fn = ewiki_pmd_by("fn");
504
505    #-- from which file
506    $new = array();
507    dialog::edit(".\$ini", $set[".\$ini"], "Import configuration settings from .ini file", "Select the .ini file to load. Most current configuration settings will be forgotten.");
508    if ($dialog_exit) { return; }
509
510    #-- read in
511    if ($txt = file_get_contents($set[".\$ini"])) {
512       #-- database
513       if (preg_match("/^ *init *= *([^\n]+)/m", $txt, $uu)) {
514          $new["DB_INIT"] = $uu[1];
515       }
516       #-- plugins
517       if (preg_match_all("/^ *load *= *([^\s]+)/m", $txt, $uu)) {
518          foreach ($uu[1] as $i=>$fn) {
519             if (! ($id = $pmd_by_fn[$fn])) {
520                if (preg_match("/(^|\/)([-\d\w_]+)\.php$/m", $fn, $uu)) {
521                   $id = $uu[2];
522                }
523                else {
524                   $id = $fn;   // (useless)
525                }
526             }
527             $new[$id] = true;
528          }
529       }
530       #-- config
531       if (preg_match_all("/^ *([A-Z\$][^\s]+) *= *([^\n]+)/m", $txt, $uu)) {
532          foreach ($uu[1] as $i=>$v) {
533             $new[$uu[1][$i]] = trim(trim($uu[2][$i]), "\"");
534          }
535       }
536    }
537
538    #-- merge in old/minumum data
539    foreach ($set_init as $i=>$v) {
540       if (!isset($new[$i])) {
541          $new[$i] = isset($set[$i]) ? $set[$i] : $set_init[$i];
542       }
543    }
544    $set = $new;
545 }
546
547
548 #-- import settings from config.php (mostly guessing)
549 function m_load_php() {
550    global $set, $set_init, $dialog_exit, $ewiki_pmd;
551    $pmd_by_fn = ewiki_pmd_by("fn");
552
553    #-- from which file
554    $new = array();
555    dialog::edit(".\$php", $set[".\$php"], "Guess configuration settings from config.php script", "Choose the ewiki config script. Currently made plugin selections and option settings will get unset/replaced.");
556    if ($dialog_exit) { return; }
557
558    #-- read in
559    if ($txt = file_get_contents($set[".\$php"])) {
560       #-- database
561       if (preg_match("/\b(@*(mysql_p?connect|anydb_connect|dba_open)\(.+?\))\b/m", $txt, $uu)) {
562          $new["DB_INIT"] = preg_replace("/[\s+\"\']/", "", $uu[1]);
563       }
564       #-- plugins
565       if (preg_match_all("/^ *@*include(?:_once)? *\(? *[\"\']([^\s\"\']+)/m", $txt, $uu)) {
566          foreach ($uu[1] as $i=>$fn) {
567             if ($id = $pmd_by_fn[$fn]) {
568                $new[$id] = true;
569             }
570             elseif (preg_match("/(^|\/)([-\d\w_]+)\.php$/m", $fn, $uu)) {
571                $new[$uu[2]] = true;
572             }
573          }
574       }
575       #-- config
576       if (preg_match_all("/^ *(\$[^\s]+) *= *([^\n]+) *;/m", $txt, $uu)) {
577          foreach ($uu[1] as $i=>$v) {
578             $new[$uu[1][$i]] = trim(trim($uu[2][$i]), "\"");
579          }
580       }
581       if (preg_match_all("/^ *@*define *\( *[\"\']([A-Z][^\s]+)[\"\'] *,([^\n]+)\) *;/m", $txt, $uu)) {
582          foreach ($uu[1] as $i=>$v) {
583             $new[$uu[1][$i]] = trim(trim($uu[2][$i]), "\"");
584          }
585       }
586    }
587
588    #-- merge in old/minumum data
589    foreach ($set_init as $i=>$v) {
590       if (!isset($new[$i])) {
591          $new[$i] = isset($set[$i]) ? $set[$i] : $set_init[$i];
592       }
593    }
594    $set = $new;
595 }
596
597
598
599
600 #== menu helper code =====================================================
601
602 #-- wrapper
603 function m_exit() {
604    @header("ewiki-setup: 0.7");
605    file_put_contents("tools/setup.dat", serialize($GLOBALS["set"]));
606    echo "- settings saved.\n";
607    exit;
608 }
609
610 #-- does nothing
611 function m_nop() {
612 }
613
614 #-- show readme
615 function m_help() {
616    dialog::text("doc/SetupTool", "Help");
617 }
618
619
620
621
622 #== terminal dialog ======================================================
623 class dialog {
624
625
626    #-- preparations
627    function init()
628    {
629       global $dialog_bin, $dialog_add, $dialog_exit, $dialog_help, $dialog_fix, $dialog_nobg;
630
631       #-- tweak PATH env variable for distributed `whiptail`
632       putenv("PATH=$_ENV[PATH]:".dirname(__FILE__));
633
634       #-- available tools
635       $progs = $_ENV["DISPLAY$_ENV[NO_X]"]
636       ? array(
637          "Xdialog" => array("--wrap --ignore --stderr", 1),
638 #<bogus># "gdialog" => array("", 0, -1), // new zenity wrapper is incompatible
639 #<bogus># "kdialog" => array("", 0, -1), // slow if KDE isn't already running
640 #<bogus># "zenity" => array("", 0),  // totally incompatible (a GNUish project)
641       )
642       : array(
643          "$_ENV[DIALOG]" => array("--stderr", 0),
644          "dialog" => array("--stderr ", 1),
645          "whiptail" => array("", 0),
646          "cdialog" => array("--stderr", 1),
647          array_shift(glob("/usr/src/*-2.*/scripts/lxdialog/lxdialog")) => array("", 0, 0, "_INJ_BOGUS_UNDOC_PARAM_MENU"),
648       );
649
650       #-- search binary
651       foreach ($progs as $d=>$args) {
652          if ($dialog_bin = trim(`which $d`)) {
653             list($dialog_add, $dialog_help, $dialog_nobg, $dialog_fix) = $args;
654             return;
655          }
656       }
657       die("This script requires one of the dialog utilities (cdialog, whiptail, Xdialog).\n");
658    }
659
660
661    #-- invoke dialog binary
662    function real($args, $adv="", $bg="ewiki setup/control tool")
663    {
664       global $dialog_bin, $dialog_add, $dialog_exit, $dialog_nobg;
665
666       $keytmp = "/tmp/php.dialog.keystroke.tmp." . getmypid(); 
667       if (!$dialog_add) {
668          $adv = "";  // this variant only supports most basic args
669       }
670       $cmd = "$dialog_bin";
671       if (!$dialog_nobg) { $cmd .= " --backtitle '$bg'"; }
672       $cmd .= " $dialog_add $adv $args";
673
674 #echo "CMD: $cmd\n";
675       system("$cmd >/dev/stdin 2>$keytmp", $dialog_exit);
676       $ret = trim(file_get_contents($keytmp));
677
678       unlink($keytmp);
679       return($ret);
680    }
681
682    #-- escape param list into exec string
683    function params() {
684       $s = "";
685       foreach (func_get_args() as $a) {
686          $s .= " '" . strtr($a, "'", "`") . "'";
687       }
688       return($s);
689    }
690
691
692    #-- show list
693    function menu($list, $title, $text)
694    {
695       global $dialog_bin, $dialog_add, $dialog_exit, $dialog_help, $dialog_fix;
696       if ($dialog_help) { $adv = " --item-help"; }
697       $args = "--title '$title' --menu '$text' 20 70 11 $dialog_fix";
698       foreach ($list as $n=>$l) {
699          list ($name, $line, $help, $_hfunc, $_mangle) = $l;
700 //         if ($_mangle) { $_mangle($line, $l); }
701          $args .= dialog::params($name, $line);
702          if ($dialog_help) { $args .= dialog::params($help); }
703       }
704       return dialog::real($args, $adv);
705    }
706
707
708    #-- checkbox list
709    function check($list, &$states, $title, $text)
710    {
711       global $dialog_bin, $dialog_add, $dialog_exit, $dialog_help;
712       $current = $states;
713
714       #-- args
715       $args = "--title '$title' --checklist '$text' 20 70 11";
716       if ($dialog_help) { $adv = " --help-button --item-help"; }
717       $names = array();
718       foreach ($list as $n=>$l) {
719          list ($name, $line, $help, $_hfunc, $_mangle) = $l;
720          $args .= dialog::params($name, $line, ($current[$name]? "on":"off"));
721          if ($dialog_help) { $args .= dialog::params($help); }
722          $names[] = $name;
723       }
724
725       #-- display
726       do {
727          $rs = dialog::real($args, $adv);
728          if ($dialog_exit == "0") {
729             foreach ($names as $name) {
730                $current[$name] = strpos(" $rs", "\"$name\"")?true:false;
731                $set = $current;
732             }
733          }
734          if (substr($rs, 0, 5) == "HELP ") {
735             m_plugin_info(substr($rs, 5));
736             $rs="HELP";
737          }
738       }
739       while ($rs == "HELP");
740
741       #-- store
742       if (($dialog_exit == "0") && isset($set)) {
743          foreach ($names as $name) {
744             $current[$name] = strpos(" $rs", "\"$name\"")?true:false;
745          }
746          $states = $current;
747       }
748    }
749
750
751    #-- input box
752    function edit($name, &$var, $title="Change", $help="")
753    {
754       global $dialog_bin, $dialog_add, $dialog_exit;
755       $var = dialog::real("--title '$title' --inputbox '\n$help\n' 14 70 '$var'");
756    }
757
758
759    #-- flags
760    function yesno($name, &$var, $title="Change", $help="")
761    {
762       global $dialog_bin, $dialog_add, $dialog_exit;
763       dialog::real("--title '$title' --yesno '$help' 15 60");
764       $c = $dialog_exit;
765       if (($c==0)||($c==1)) {
766          $var = 1 - $c;   //0=Yes, 1=No
767       }
768    }
769
770
771    #-- show file
772    function text($file, $title)
773    {
774       global $dialog_bin, $dialog_add, $dialog_exit;
775 #      $file = dialog::params(file_get_contents($file));
776       dialog::real("--title '$title' --textbox $file 21 72");
777    }
778
779 }
780
781
782 #-- gauge display
783 function d_gauge($i=0, $max=0, $title="initializing from *.meta data files", $pause=15000, $every=15)
784 {
785    global $dialog_bin;
786    static $p, $last_max;
787
788    #-- clean up again
789    if ($p && !$max) {
790       pclose($p);
791       $p = NULL;
792       $last_max = 0;
793       return;
794    }
795    #-- init
796    elseif (!isset($p) || ($last_max != $max)) {
797       $p = popen("$dialog_bin --gauge '$title' 7 72 000", "w");
798       $last_max = $max;
799    }
800
801    #-- output
802    if ($i && $max) {
803       $percent = (int) (100 * $i / $max);
804       fwrite($p, "$percent\n");
805
806       #-- delay
807       if (0 == $i % $every) {
808          if (function_exists("usleep")) { usleep($pause); }
809       }
810    }
811 }
812
813
814
815 ?>