+
+# quotes string written in single quotes
+sub quote_single($) {
+ my $string = shift(@_);
+ $string =~ s/\'/\\'/g;
+ return $string;
+}
+
+# determine a plugin's version number
+#
+# parses the setup.php file, looking for the
+# version string in the <plugin>_info() or the
+# <plugin>_version functions.
+#
+sub get_plugin_version() {
+
+ my $plugin_name = shift(@_);
+
+ $setup_file = '../plugins/' . $plugin_name . '/setup.php';
+ if ( -e "$setup_file" ) {
+ # Make sure that file is readable
+ if (! -r "$setup_file") {
+ print "\n";
+ print "WARNING:\n";
+ print "The file \"$setup_file\" was found, but you don't\n";
+ print "have rights to read it. The plugin \"";
+ print $plugin_name . "\" may not work correctly until you fix this.\n";
+ print "\nPress enter to continue";
+ $ctu = <STDIN>;
+ print "\n";
+ next;
+ }
+
+ $version = ' ';
+# FIXME: grep the file instead of reading it into memory?
+ $whole_file = '';
+ open( FILE, "$setup_file" );
+ while ( $line = <FILE> ) {
+ $whole_file .= $line;
+ }
+ close(FILE);
+
+ # ideally, there is a version in the <plugin>_info function...
+ #
+ if ($whole_file =~ /('version'\s*=>\s*['"](.*?)['"])/) {
+ $version .= $2;
+
+ # this assumes there is only one function that returns
+ # a static string in the setup file
+ #
+ } elsif ($whole_file =~ /(return\s*['"](.*?)['"])/) {
+ $version .= $2;
+ }
+
+ return $version;
+
+ } else {
+ print "\n";
+ print "WARNING:\n";
+ print "The file \"$setup_file\" was not found.\n";
+ print "The plugin \"" . $plugin_name;
+ print "\" may not work correctly until you fix this.\n";
+ print "\nPress enter to continue";
+ $ctu = <STDIN>;
+ print "\n";
+ next;
+ }
+
+}
+
+# determine a plugin's English name
+#
+# parses the setup.php file, looking for the
+# English name in the <plugin>_info() function.
+#
+sub get_plugin_english_name() {
+
+ my $plugin_name = shift(@_);
+
+ $setup_file = '../plugins/' . $plugin_name . '/setup.php';
+ if ( -e "$setup_file" ) {
+ # Make sure that file is readable
+ if (! -r "$setup_file") {
+ print "\n";
+ print "WARNING:\n";
+ print "The file \"$setup_file\" was found, but you don't\n";
+ print "have rights to read it. The plugin \"";
+ print $plugin_name . "\" may not work correctly until you fix this.\n";
+ print "\nPress enter to continue";
+ $ctu = <STDIN>;
+ print "\n";
+ next;
+ }
+
+ $english_name = '';
+# FIXME: grep the file instead of reading it into memory?
+ $whole_file = '';
+ open( FILE, "$setup_file" );
+ while ( $line = <FILE> ) {
+ $whole_file .= $line;
+ }
+ close(FILE);
+
+ # the English name is in the <plugin>_info function or nothing...
+ #
+ if ($whole_file =~ /('english_name'\s*=>\s*['"](.*?)['"])/) {
+ $english_name .= $2;
+ }
+
+ return $english_name;
+
+ } else {
+ print "\n";
+ print "WARNING:\n";
+ print "The file \"$setup_file\" was not found.\n";
+ print "The plugin \"" . $plugin_name;
+ print "\" may not work correctly until you fix this.\n";
+ print "\nPress enter to continue";
+ $ctu = <STDIN>;
+ print "\n";
+ next;
+ }
+
+}
+
+# parses the setup.php files for all activated plugins and
+# builds static plugin hooks array so we don't have to load
+# ALL plugins are runtime and build the hook array on every
+# page request
+#
+# hook array is saved in config/plugin_hooks.php
+#
+# Note the $verbose variable at the top of this routine
+# can be set to zero to quiet it down.
+#
+# NOTE/FIXME: we aren't necessarily interested in writing
+# a full-blown PHP parsing engine, so plenty
+# of assumptions are included herein about the
+# coding of the plugin setup files, and things
+# like commented out curly braces or other
+# such oddities can break this in a bad way.
+#
+sub build_plugin_hook_array() {
+
+ $verbose = 1;
+
+ if ($verbose) {
+ print "\n\n";
+ }
+
+ if ( open( HOOKFILE, ">plugin_hooks.php" ) ) {
+ print HOOKFILE "<?php\n";
+ print HOOKFILE "\n";
+
+ print HOOKFILE "/**\n";
+ print HOOKFILE " * SquirrelMail Plugin Hook Registration File\n";
+ print HOOKFILE " * Auto-generated using the configure script, conf.pl\n";
+ print HOOKFILE " */\n";
+ print HOOKFILE "\n";
+ print HOOKFILE "global \$squirrelmail_plugin_hooks;\n";
+ print HOOKFILE "\n";
+
+PLUGIN: for ( $ct = 0 ; $ct <= $#plugins ; $ct++ ) {
+
+ if ($verbose) {
+ print "Activating plugin \"" . $plugins[$ct] . "\"...\n";
+ }
+
+ $setup_file = '../plugins/' . $plugins[$ct] . '/setup.php';
+ if ( -e "$setup_file" ) {
+ # Make sure that file is readable
+ if (! -r "$setup_file") {
+ print "\n";
+ print "WARNING:\n";
+ print "The file \"$setup_file\" was found, but you don't\n";
+ print "have rights to read it. The plugin \"";
+ print $plugins[$ct] . "\" will not be activated until you fix this.\n";
+ print "\nPress enter to continue";
+ $ctu = <STDIN>;
+ print "\n";
+ next;
+ }
+ open( FILE, "$setup_file" );
+ $inside_init_fxn = 0;
+ $brace_count = 0;
+ while ( $line = <FILE> ) {
+
+ # throw away lines until we get to target function
+ #
+ if (!$inside_init_fxn
+ && $line !~ /^\s*function\s*squirrelmail_plugin_init_/i) {
+ next;
+ }
+ $inside_init_fxn = 1;
+
+
+ # count open braces
+ #
+ if ($line =~ /{/) {
+ $brace_count++;
+ }
+
+
+ # count close braces
+ #
+ if ($line =~ /}/) {
+ $brace_count--;
+
+ # leaving <plugin>_init() function...
+ if ($brace_count == 0) {
+ close(FILE);
+ next PLUGIN;
+ }
+
+ }
+
+
+ # throw away lines that are not exactly one "brace set" deep
+ #
+ if ($brace_count > 1) {
+ next;
+ }
+
+
+ # also not interested in lines that are not
+ # hook registration points
+ #
+ if ($line !~ /^\s*\$squirrelmail_plugin_hooks/i) {
+ next;
+ }
+
+
+ # if $line does not have an ending semicolon,
+ # we need to recursively read in subsequent
+ # lines until we find one
+ while ( $line !~ /;\s*$/ ) {
+ $line =~ s/[\n\r]\s*$//;
+ $line .= <FILE>;
+ }
+
+
+ $line =~ s/^\s+//;
+ $line =~ s/^\$//;
+ $var = $line;
+
+ $var =~ s/=/EQUALS/;
+ if ( $var =~ /^([a-z])/i ) {
+ @options = split ( /\s*EQUALS\s*/, $var );
+ $options[1] =~ s/[\n\r]//g;
+ $options[1] =~ s/[\'\"];\s*$//;
+ $options[1] =~ s/;$//;
+ $options[1] =~ s/^[\'\"]//;
+ # de-escape escaped strings
+ $options[1] =~ s/\\'/'/g;
+ $options[1] =~ s/\\\\/\\/g;
+
+ if ( $options[0] =~ /^squirrelmail_plugin_hooks\s*\[\s*['"]([a-z0-9 \/._*-]+)['"]\s*\]\s*\[\s*['"]([0-9a-z._-]+)['"]\s*\]/i ) {
+ $hook_name = $1;
+ $hooked_plugin_name = $2;
+ # Note: if we wanted to stop plugins from registering
+ # a *different* plugin on a hook, we could catch
+ # it here, however this has actually proven to be
+ # a useful *feature*
+ #if ($hooked_plugin_name ne $plugins[$ct]) {
+ # print "...plugin is tring to hook in under different name...\n";
+ #}
+
+#FIXME: do we want to count the number of hook registrations for each plugin and warn if a plugin doesn't have any?
+ # hook registration has been found!
+ if ($verbose) {
+ if ($hooked_plugin_name ne $plugins[$ct]) {
+ print " registering on hook \"" . $hook_name . "\" (as \"$hooked_plugin_name\" plugin)\n";
+ } else {
+ print " registering on hook \"" . $hook_name . "\"\n";
+ }
+ }
+ $line =~ s/ {2,}/ /g;
+ $line =~ s/=/\n =/;
+ print HOOKFILE "\$$line";
+
+ }
+
+ }
+
+ }
+ close(FILE);
+
+ } else {
+ print "\n";
+ print "WARNING:\n";
+ print "The file \"$setup_file\" was not found.\n";
+ print "The plugin \"" . $plugins[$ct];
+ print "\" will not be activated until you fix this.\n";
+ print "\nPress enter to continue";
+ $ctu = <STDIN>;
+ print "\n";
+ next;
+ }
+
+ }
+
+ print HOOKFILE "\n\n";
+ close(HOOKFILE);
+# if ($verbose) {
+ print "\nDone activating plugins; registration data saved in plugin_hooks.php\n\n";
+# }
+
+ } else {
+
+ print "\n";
+ print "WARNING:\n";
+ print "The file \"plugin_hooks.php\" was not able to be written to.\n";
+ print "No plugins will be activated until you fix this.\n";
+ print "\nPress enter to continue";
+ $ctu = <STDIN>;
+ print "\n";
+
+ }
+
+}
+
+# converts (binary) integer values that correspond
+# to the SquirrelMail debug mode constants (see
+# include/constants.php) into those constant strings
+# (bitwise or'd if more than one is enabled)
+#
+# if the value passed in is not an integer, it is
+# returned unmolested
+#
+sub convert_debug_binary_integer_to_constants() {
+
+ my ($debug_mode) = @_;
+ if ($debug_mode =~ /^[^0-9]/) {
+ return $debug_mode;
+ }
+ $debug_mode = int($debug_mode);
+ $new_debug_mode = '';
+
+ # per include/constants.php, here are their values:
+ #
+ # 0 SM_DEBUG_MODE_OFF
+ # 1 SM_DEBUG_MODE_SIMPLE
+ # 512 SM_DEBUG_MODE_MODERATE
+ # 524288 SM_DEBUG_MODE_ADVANCED
+ # 536870912 SM_DEBUG_MODE_STRICT
+ #
+ if ($debug_mode & 1) {
+ $new_debug_mode .= ' | SM_DEBUG_MODE_SIMPLE';
+ }
+ if ($debug_mode & 512) {
+ $new_debug_mode .= ' | SM_DEBUG_MODE_MODERATE';
+ }
+ if ($debug_mode & 524288) {
+ $new_debug_mode .= ' | SM_DEBUG_MODE_ADVANCED';
+ }
+ if ($debug_mode & 536870912) {
+ $new_debug_mode .= ' | SM_DEBUG_MODE_STRICT';
+ }
+
+ $new_debug_mode =~ s/^ \| //;
+ if (!$new_debug_mode) {
+ $new_debug_mode = 'SM_DEBUG_MODE_OFF';
+ }
+
+ return $new_debug_mode;
+}
+
+# converts SquirrelMail debug mode constants (see
+# include/constants.php) into their corresponding
+# (binary) integer values
+#
+# if the value passed in is an integer already, it
+# is returned unmolested
+#
+sub convert_debug_constants_to_binary_integer() {
+
+ my ($debug_mode) = @_;
+ if ($debug_mode =~ /^[0-9]/) {
+ return $debug_mode;
+ }
+ $new_debug_mode = 0;
+
+ # per include/constants.php, here are their values:
+ #
+ # 0 SM_DEBUG_MODE_OFF
+ # 1 SM_DEBUG_MODE_SIMPLE
+ # 512 SM_DEBUG_MODE_MODERATE
+ # 524288 SM_DEBUG_MODE_ADVANCED
+ # 536870912 SM_DEBUG_MODE_STRICT
+ #
+ if ($debug_mode =~ /\bSM_DEBUG_MODE_OFF\b/) {
+ $new_debug_mode = 0;
+ }
+ if ($debug_mode =~ /\bSM_DEBUG_MODE_SIMPLE\b/) {
+ $new_debug_mode |= 1;
+ }
+ if ($debug_mode =~ /\bSM_DEBUG_MODE_MODERATE\b/) {
+ $new_debug_mode |= 512;
+ }
+ if ($debug_mode =~ /\bSM_DEBUG_MODE_ADVANCED\b/) {
+ $new_debug_mode |= 524288;
+ }
+ if ($debug_mode =~ /\bSM_DEBUG_MODE_STRICT\b/) {
+ $new_debug_mode |= 536870912;
+ }
+
+ return $new_debug_mode;
+}
+
+# Function to print n column numbered lists
+#
+# WARNING: the names in the list will be truncated
+# to fit in their respective columns based on the
+# screen width and number of columns.
+#
+# Expected arguments (in this order):
+#
+# * The start number to use for the list
+# * The number of columns to use
+# * The screen width
+# * Boolean (zero/one), indicating
+# whether or not to show item numbers
+# * The list of strings to be shown
+#
+# Returns: The number printed on screen of the last item in the list
+#
+sub print_multi_col_list {
+ my ($num, $cols, $screen_width, $show_numbering, @list) = @_;
+ my $x;
+ my $col_cnt = 0;
+ my $row_cnt = 0;
+ my $rows;
+ my $col_width;
+ my $total = 0;
+ my @layout = ();
+ my @numbers = ();
+
+ $rows = int(@list / $cols);
+ if (@list % $cols) { $rows++; }
+ if ($show_numbering) { $col_width = int(($screen_width - 2) / $cols) - 5; }
+ else { $col_width = int(($screen_width - 2) / $cols) - 2; }
+
+ # build the layout array so numbers run down each column
+ #
+ for ( $x = 0; $x < @list; $x++ ) {
+
+ $layout[$row_cnt][$col_cnt] = $list[$x];
+ $numbers[$row_cnt][$col_cnt] = $num++;
+
+ # move to next column
+ #
+ if ($row_cnt == $rows - 1) {
+ $row_cnt = 0;
+ $col_cnt++;
+ }
+ else { $row_cnt++; }
+
+ }
+
+ # if we filled up fewer rows than needed, recalc column width
+ #
+ if ($rows * $col_cnt == @list) { $col_cnt--; } # loop above ended right after increment
+ if ($col_cnt + 1 < $cols) {
+ if ($show_numbering) { $col_width = int(($screen_width - 2) / ($col_cnt + 1)) - 5; }
+ else { $col_width = int(($screen_width - 2) / ($col_cnt + 1)) - 2; }
+ }
+
+ # print it
+ # iterate rows
+ #
+ for ( $row_cnt = 0; $row_cnt <= $rows; $row_cnt++ ) {
+
+ # indent the row
+ #
+ print " ";
+
+ # iterate columns for this row
+ #
+ for ( $col_cnt = 0; $col_cnt <= $cols; $col_cnt++ ) {
+ if ($layout[$row_cnt][$col_cnt]) {
+ print " ";
+ if ($show_numbering) { printf "$WHT% 2u.$NRM", $numbers[$row_cnt][$col_cnt]; }
+ printf " %-$col_width." . $col_width . "s", $layout[$row_cnt][$col_cnt];
+ }
+ }
+ print "\n";
+ }
+
+
+ return $num - 1;
+}
+