php IHDR w Q )Ba pHYs sRGB gAMA a IDATxMk\U s&uo,mD )Xw+e?tw.oWp;QHZnw`gaiJ9̟灙a=nl[ ʨ G;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ w@H;@ q$ y H@E7j 1j+OFRg}ܫ;@Ea~ j`u'o> j- $_q?qS XzG'ay
files >> /var/www/html/sub/images/sym/root/usr/libexec/webmin/virtual-server-mobile/ |
files >> /var/www/html/sub/images/sym/root/usr/libexec/webmin/virtual-server-mobile/theme.pl |
# Theme-level UI override functions # XXX Usermin mailbox module support # XXX nicer mail / folder lists for iPhone # XXX icons next to folders # XXX next/prev navigator # XXX prefs on every page?? # Disable buttons on edit_domain page $main::basic_virtualmin_domain = 1; # Disable other links on virtualmin module main page $main::basic_virtualmin_menu = 1; $main::nocreate_virtualmin_menu = 1; # Tell CGIs that uploads are not possible $main::no_browser_uploads = 1; # The theme will provide links for VM2 $main::cloudmin_no_create_links = 1; $main::cloudmin_no_edit_buttons = 1; $main::cloudmin_no_global_links = 1; sub theme_ui_post_header { local ($text) = @_; local $rv; if ($text) { $rv .= "<div type=panel>\n" if ($main::theme_iui_no_default_div); print "<div class=linksbar>\n"; print "<h2>$text</h2>\n"; print "</div>\n"; $rv .= "</div>\n" if ($main::theme_iui_no_default_div); } return $rv; } sub theme_ui_pre_footer { return ""; } # theme_footer([page, name]+, [noendbody]) # Output a footer for returning to some page sub theme_footer { local $i; local @links; local %module_info = get_module_info(get_module_name()); for($i=0; $i+1<@_; $i+=2) { local $url = $_[$i]; if ($url ne '/' || !$tconfig{'noindex'}) { if ($url eq '/') { # Don't change link to / $url = "/"; } elsif ($url eq '' && get_module_name() eq 'virtual-server' || $url eq '/virtual-server/') { # Don't bother with virtualmin menu, unless the current # page is view/edit_domain.cgi, in which case link # back to index_edit.cgi if ($0 =~ /(view|edit)_domain.cgi/ && $in{'dom'} && get_module_name() eq 'virtual-server') { $url = "/index_edit.cgi?dom=$in{'dom'}"; } else { next; } } elsif ($url eq '' && get_module_name() eq 'server-manager' || $url eq '/server-manager/') { # Don't bother with VM2 menu, unless the current page # is edit_serv.cgi if ($0 =~ /edit_serv.cgi/ && $in{'id'} && get_module_name() eq 'server-manager') { $url = "/index_system.cgi?id=$in{'id'}"; } else { next; } } elsif ($url eq '' && get_module_name() eq 'mailbox') { # Don't bother with link to mail list from # pages other than view/reply mail if ($0 =~ /list_(folders|ifolders).cgi/ || $0 =~ /list_addresses.cgi/ || $0 =~ /edit_sig.cgi/ || $0 =~ /edit_(folder|ifolder|virt|imap|pop3|comp).cgi/) { next; } } elsif ($url =~ /^\/mailbox(|\/|index.cgi)$/) { # For links to read mail from other modules, link # to the main menu (ie. preferences) next; } elsif ($url eq '' && get_module_name()) { $url = "/".get_module_name()."/". $module_info{'index_link'}; } elsif ($url =~ /^\?/ && get_module_name()) { $url = "/".get_module_name()."/$url"; } elsif ($url =~ /(edit|view)_domain.cgi\?dom=(\d+)/) { # Force links back to edit form to domain options list $url = "/index_edit.cgi?dom=$2"; } elsif ($url =~ /edit_serv.cgi\?id=(\d+)/) { # Force links back to edit form to system options list $url = "/index_system.cgi?id=$1"; } $url = "$gconfig{'webprefix'}$url" if ($url =~ /^\//); push(@links, [ $url, &text('main_return', $_[$i+1]) ]); } } if (&theme_use_iui()) { # Close main body div if (!$main::theme_iui_no_default_div) { print "</div>\n"; } # Output toolbar, if needed if (@links) { # Use first link from footer $theme_iui_toolbar_index = $links[0]->[0]; } if (!$main::theme_iui_no_default_div && !$theme_iui_toolbar_index && $remote_user) { # For pages other than the main index, always have a backlink # (assuming we are logged in) $theme_iui_toolbar_index = "/"; } if ($theme_iui_toolbar_title || $theme_iui_toolbar_index || $theme_iui_toolbar_button || $main::theme_iui_no_default_div) { print "<div class='toolbar'>\n"; if ($theme_iui_toolbar_title) { # Title of page, full width if no buttons if ($theme_iui_toolbar_index || $main::theme_iui_no_default_div || $theme_iui_toolbar_button) { print "<h1 id='pageTitle'></h1>\n"; } else { print "<h2 id='pageTitle'></h2>\n"; } } if ($theme_iui_toolbar_index) { print "<a class='button indexButton' href='$theme_iui_toolbar_index' target=_self>Back</a>\n"; } if ($main::theme_iui_no_default_div) { print "<a id='backButton' class='button' href='#'></a>\n"; } if ($theme_iui_toolbar_button) { local $t = $theme_iui_toolbar_button->[0] =~ /help.cgi/ ? "target=_new" : "target=_self"; print "<a class='button' href='$theme_iui_toolbar_button->[0]' $t>$theme_iui_toolbar_button->[1]</a>\n"; } print "</div>\n"; } } else { # As bar-separated list print join(" | ", map { "<a href='$_->[0]'><- $_->[1]</a>" } @links),"\n"; } if (!$_[$i]) { print "</body></html>\n"; } } # theme_ui_table_start(heading, [tabletags], [cols]) # A table with a heading and table inside sub theme_ui_table_start { local ($heading, $tabletags, $cols) = @_; local $rv; if (&theme_use_iui() && $theme_iui_fieldset_table) { # Use IUI field set $rv .= "<fieldset>\n"; $rv .= "<div class=rowhead>$heading</div>\n" if (defined($heading)); } elsif (&theme_use_iui()) { # Start a styled block for the table $rv .= "<div class='webminTable'>\n"; if (defined($heading)) { $rv .= "<div class='webminTableHeader'>$heading</div>\n"; } $rv .= "<div class='webminTableBody'>\n"; } else { # Table is just elements below each other $rv .= "<font size=+1>$heading</font><br>\n" if (defined($heading)); $rv .= "<hr>\n"; } $main::ui_table_cols = 2; $main::ui_table_pos = 0; return $rv; } # theme_ui_table_end() # The end of a table started by ui_table_start sub theme_ui_table_end { if (&theme_use_iui() && $theme_iui_fieldset_table) { return "</fieldset>\n"; } elsif (&theme_use_iui()) { return "</div></div>\n"; } else { return "<hr>\n"; } } # theme_ui_table_row(label, value, [cols], [&td-tags]) # Returns HTML for a row in a table started by ui_table_start, with a 1-column # label and 1+ column value. sub theme_ui_table_row { local ($label, $value, $cols) = @_; local $rv; if (&theme_use_iui() && $theme_iui_fieldset_table) { # Use IUI field set $rv .= "<div class=row>\n"; $rv .= "<label>$label</label>\n" if ($label =~ /\S/); $rv .= "<div class=rowvalue>$value</div>\n"; $rv .= "</div>\n"; } elsif (&theme_use_iui()) { # Styles label and value if ($label =~ /\S/) { $rv .= "<div class='webminTableName'>$label</div>\n"; } $rv .= "<div class='webminTableValue'>$value</div>\n"; } else { # Label and value are above each other $rv .= "<b>$label</b><br>\n" if ($label =~ /\S/); #$rv .= " " if (defined($label) && # $value !~ /^\s*<table/ && # $value !~ /^\s*<!--grid/); $rv .= "$value<br>\n"; } return $rv; } # theme_ui_hidden_table_row_start(label, name, flag) # On the iPhone, returns a collapsible section start. On other devices, does # nothing as CSS isn't supported. sub theme_ui_hidden_table_row_start { local ($label, $name, $flag) = @_; if (&theme_use_iui()) { my $rv = &theme_ui_hidden_start($label, $name, $flag); return $rv; } else { return ""; } } sub theme_ui_hidden_table_row_end { local ($name) = @_; if (&theme_use_iui()) { return &theme_ui_hidden_end($name); } else { return ""; } } # theme_ui_hidden_table_start sub theme_ui_hidden_table_start { local ($heading, $tabletags, $cols, $name, $status) = @_; if (&theme_use_iui() && !$theme_iui_fieldset_table) { # Start a CSS / javascript collapsible table for the iPhone local $rv = "<div class='webminTable'>\n"; local $openid = "hiddenopener_".$name; local $divid = "hiddendiv_".$name; local $opencls = $status ? "webminTableHeaderOpen" : "webminTableHeaderClosed"; local $divcls = $status ? "webminTableBodyOpen" : "webminTableBodyClosed"; $rv .= "<div class=webminTableHeader><a class='$opencls' ". "href='javascript:openCloseTable(\"$openid\", \"$divid\")' ". "id='$openid'>$heading</a></div>\n"; $rv .= "<div class='$divcls' id='$divid'>\n"; return $rv; } else { # Just output a normal table start, as mobile browsers don't support CSS return &theme_ui_table_start($heading, $tabletags, $cols); } } # theme_ui_hidden_table_end # Just outputs a normal table end, as mobile browsers don't support CSS sub theme_ui_hidden_table_end { local ($heading, $tabletags, $cols, $name, $status) = @_; return &theme_ui_table_end($heading, $tabletags, $cols); } # theme_ui_columns_start(&headings, [width-percent], [noborder], [&tdtags], [heading]) # Returns HTML for a multi-column table, with the given headings sub theme_ui_columns_start { local ($heads, $width, $noborder, $tdtags, $heading) = @_; local $rv; $main::theme_ui_columns_folders = 0; $main::theme_ui_columns_search = 0; $main::theme_ui_columns_filter = 0; if (get_module_name() eq 'mailbox' && $0 =~ /list_(i?)folders.cgi/) { # For folders list, use different format $main::theme_ui_columns_folders = 1; } elsif (get_module_name() eq 'mailbox' && $0 =~ /search_form.cgi/) { # For search form $main::theme_ui_columns_search = 1; } elsif (get_module_name() eq 'filter' && $0 =~ /index.cgi/) { # For filter list $main::theme_ui_columns_filter = 1; } else { # Just regular plain table $rv .= "<table".($noborder ? "" : " border"). (defined($width) ? " width=$width%" : ""). " class='ui_columns'>\n"; if ($heading) { $rv .= "<font size=+1>$heading</font><br>\n"; } $rv .= "<tr class='ui_columns_heads'>\n"; local $i; for($i=0; $i<@$heads; $i++) { $rv .= "<th ".$tdtags->[$i].">". (&theme_use_iui() ? "" : "<b>"). ($heads->[$i] eq "" ? "<br>" : $heads->[$i]). (&theme_use_iui() ? "" : "</b>")."</th>\n"; } $rv .= "</tr>\n"; } return $rv; } # theme_ui_columns_row(&columns, &tdtags) # Returns HTML for a row in a multi-column table sub theme_ui_columns_row { local ($cols, $tdtags) = @_; local $rv; if ($main::theme_ui_columns_folders) { # Show each row of folders as a block local %ttext = &load_language($current_theme); local $cb = &ui_checkbox("x", "x", undef, 0, undef, 1); local @c = @$cols; splice(@c, 2, 0, undef) if ($0 =~ /list_ifolders.cgi/); $rv .= ($c[0] || $cb); $rv .= $c[1]."<br>\n"; if ($c[2]) { $rv .= "<b>$ttext{'folders_loc'}</b> ".$c[2]."<br>\n"; } $rv .= "<b>$ttext{'folders_ty'}</b> ".$c[3].", ".$c[4]."<br>\n"; if ($c[5] =~ /\S/) { $rv .= "<b>$ttext{'folders_acts'}</b> ".$c[5]."<br>\n"; } } elsif ($main::theme_ui_columns_search) { # Show each search term as a block local %ttext = &load_language($current_theme); local $neg = $cols->[2]; if ($neg =~ /(neg_\d+)/) { $neg = &ui_checkbox("$1", 1, $ttext{'search_neg'}, 0); } $rv .= "<b>$ttext{'search_field'}</b> ".$cols->[1]."<br>\n"; $rv .= "<b>$ttext{'search_text'}</b> ".$cols->[4].$neg."<br>\n"; } elsif ($main::theme_ui_columns_filter) { # Show each filter as a block local %ttext = &load_language($current_theme); local $cb = &ui_checkbox("x", "x", undef, 0, undef, 1); $rv .= ($cols->[0] || $cb); local $cond = $cols->[1]; if ($cond =~ /^<([^>]*)>(.*)<\/a>$/) { local ($href, $txt) = ($1, $2); if (length($txt) > 40) { $txt = substr($txt, 0, 40); if ($txt =~ /<[^>]*$/) { $txt .= ">"; # Close HTML } $txt .= ".."; } $cond = "<$href>$txt</a>"; } $rv .= $cond."<br>\n"; $rv .= "<b>$ttext{'filter_act'}</b> $cols->[2]<br>\n"; if ($cols->[3]) { $rv .= "<b>$ttext{'filter_move'}</b> $cols->[3]<br>\n"; } } else { # Regular table $rv .= "<tr class='ui_columns_row'>\n"; local $i; for($i=0; $i<@$cols; $i++) { $rv .= "<td ".$tdtags->[$i]." class='ui_columns_cell'>". ($cols->[$i] eq "" ? "<br>" : $cols->[$i])."</td>\n"; } $rv .= "</tr>\n"; } return $rv; } # theme_ui_columns_header(&columns, &tdtags) # Returns HTML for a row in a multi-column table, with a header background sub theme_ui_columns_header { local ($cols, $tdtags) = @_; local $rv; $rv .= "<tr class='ui_columns_header'>\n"; local $i; for($i=0; $i<@$cols; $i++) { $rv .= "<th ".$tdtags->[$i].">". (&theme_use_iui() ? "" : "<b>"). ($cols->[$i] eq "" ? "<br>" : $heads->[$i]). (&theme_use_iui() ? "" : "</b>")."</th>\n"; } $rv .= "</tr>\n"; return $rv; } # theme_ui_checked_columns_row(&columns, &tdtags, checkname, checkvalue, [checked?]) # Returns HTML for a row in a multi-column table, in which the first # column is a checkbox sub theme_ui_checked_columns_row { local ($cols, $tdtags, $checkname, $checkvalue, $checked) = @_; local $rv; local $cb = &ui_checkbox($checkname, $checkvalue, undef, $checked); if ($main::theme_ui_columns_folders || $main::theme_ui_columns_filter) { $rv = &theme_ui_columns_row([ $cb, @$cols ], $tdtags); } else { $rv .= "<tr class='ui_checked_columns'>\n"; $rv .= "<td ".$tdtags->[0].">".$cb."</td>\n"; local $i; for($i=0; $i<@$cols; $i++) { $rv .= "<td ".$tdtags->[$i+1].">"; $rv .= ($cols->[$i] eq "" ? "<br>" : $cols->[$i]); $rv .= "</td>\n"; } $rv .= "</tr>\n"; } return $rv; } # theme_ui_radio_columns_row(&columns, &tdtags, checkname, checkvalue) # Returns HTML for a row in a multi-column table, in which the first # column is a radio button sub theme_ui_radio_columns_row { local ($cols, $tdtags, $checkname, $checkvalue) = @_; local $rv; $rv .= "<tr class='ui_radio_columns'>\n"; $rv .= "<td ".$tdtags->[0].">". &ui_oneradio($checkname, $checkvalue, "", 0)."</td>\n"; local $i; for($i=0; $i<@$cols; $i++) { $rv .= "<td ".$tdtags->[$i+1].">"; $rv .= ($cols->[$i] !~ /\S/ ? "<br>" : $cols->[$i]); $rv .= "</td>\n"; } $rv .= "</tr>\n"; return $rv; } # theme_ui_columns_end() # Returns HTML to end a table started by ui_columns_start sub theme_ui_columns_end { if ($main::theme_ui_columns_folders || $main::theme_ui_columns_search || $main::theme_ui_columns_filter) { return ""; } return "</table>\n"; } # theme_select_all_link(field, form, text) # Returns nothing, because javascript is assumed not to work sub theme_select_all_link { return undef; } # theme_select_invert_link(field, form, text) # Returns nothing, because javascript is assumed not to work sub theme_select_invert_link { return undef; } # theme_ui_hidden_start(title, name, status, url) # For the iPhone, returns the normal collapsible section. For others, returns # a link that may halt other output if not open. sub theme_ui_hidden_start { local ($title, $name, $status, $url) = @_; local $rv; if (&theme_use_iui()) { # Real CSS / javascript collapsing section local $openid = "hiddenopener_".$name; local $divid = "hiddendiv_".$name; local $opencls = $status ? "openerOpen" : "openerClosed"; local $divcls = $status ? "hiddenOpen" : "hiddenClosed"; $rv .= "<a href='javascript:openCloseHidden(\"$openid\", \"$divid\")' ". "class='$opencls' id='$openid'>$title</a><br>\n"; $rv .= "<div class='$divcls' id='$divid'>\n"; } else { # Fake it by redirecting output to nowhere local $nstatus = $status ? 0 : 1; print $status ? "-" : "+"; $rv .= " <a href='$url?$name=$nstatus'>$title</a><br>\n"; if (!$status) { open(NULLFILE, ">$null_file"); $main::suppressing_hidden_start = select(NULLFILE); } else { $main::suppressing_hidden_start = undef; } } return $rv; } # theme_ui_hidden_end(name) sub theme_ui_hidden_end { local ($name) = @_; if (&theme_use_iui()) { # Close hiding div return "</div>\n"; } else { # Stop supressing output if ($main::suppressing_hidden_start) { select($main::suppressing_hidden_start); } return ""; } } # theme_ui_links_row(&links) # Returns HTML for a row of links, like select all / invert selection / add.. sub theme_ui_links_row { local ($links) = @_; local @nn = grep { $_ ne "" } @$links; return @nn ? join(" | ", @nn)."<br>\n" : ""; } sub theme_ui_yesno_radio { local ($name, $value, $yes, $no, $dis) = @_; $yes = 1 if (!defined($yes)); $no = 0 if (!defined($no)); $value = int($value); if (&theme_use_iui()) { # iPhone-style slider local $rv; local $tog = $value == $yes ? "true" : "false"; $rv .= "<div class='row'><div id='${name}_toggle' class='toggle' toggled='$tog' onClick='var h = document.getElementById(\"$name\"); h.value = getAttribute(\"toggled\") == \"true\" ? \"$yes\" : \"$no\";'><span class='thumb'></span><span class='toggleOn'>$text{'yes'}</span><span class='toggleOff'>$text{'no'}</span></div></div>"; $rv .= "<input type=hidden name=\""."e_escape($name)."\" ". "id=\""."e_escape($name)."\" ". "value=\""."e_escape($value)."\">"; return $rv; } else { # Regular input return &ui_radio($name, $value, [ [ $yes, $text{'yes'} ], [ $no, $text{'no'} ] ], $dis); } } # theme_ui_print_header(subtext, args...) # If called with "In domain XXX" as the subtext, put it after the title sub theme_ui_print_header { local ($subtext, @args) = @_; if (!&theme_use_iui()) { # Put domain name in title, with [ ] local $re = $text{'indom'} || $virtual_server::text{'indom'}; $re =~ s/\$1/\(\\S+\)/; if ($subtext =~ /$re/) { $args[0] .= " [$1]"; &header(@args); return; } } # Any domain name is on its own line &header(@args); print &ui_post_header($subtext); } sub theme_redirect { local ($orig, $url) = @_; if (get_module_name() eq "virtual-server" && $url =~ /postsave.cgi\?dom=(\d+)/) { # Show domain menu after saving $url =~ s/\/([^\/]+)\/postsave.cgi/\/index_edit.cgi/g; } elsif (get_module_name() eq "server-manager" && $0 =~ /save_serv.cgi/) { # Show server menu after saving main details local $id = $url =~ /id=(\S+)/ ? $1 : $in{'id'}; if ($id) { $url =~ s/\/([^\/]+)\/index.cgi.*/\/index_system.cgi?id=$id/; } } elsif (get_module_name() eq "virtual-server" && $orig eq "" && $url =~ /^((http|https):\/\/([^\/]+))\//) { # Show templates page after saving global config $url = &theme_use_iui() ? "$1/index.cgi" : "$1/index_templates.cgi"; } print "Location: $url\n\n"; } # For each tab, output just a link sub theme_ui_tabs_start { local ($tabs, $name, $sel, $border) = @_; if (get_module_name() eq 'mailbox' && $0 =~ /reply_mail.cgi/) { # Special layout for composing email, where we can't use hiding $theme_ui_tabs_current = $tabs; return undef; } elsif (&theme_use_iui()) { # For IUI, show tabs as a spaced row of links $main::ui_tabs_selected = $sel; local $rv; $rv .= "<div class=tabsBody>"; $rv .= "<table width=100% border=0 cellpadding=0 cellspacing=0 class=tabsTable><tr>\n"; local $pc = int(100 / scalar(@$tabs)); foreach my $t (@$tabs) { my $c = $t->[0] eq $sel ? "tabsSel" : "tabsUnSel"; $rv .= "<td class='$c' id='tab_$t->[0]'><a href='' class='tabsLink' onClick='return selectTab(\"$name\", \"$t->[0]\")'>$t->[1]</a></td>\n"; } $rv .= "</tr></table>\n"; $rv .= &ui_hidden($name, $sel)."\n"; return $rv; } else { # Show list of tabs $theme_ui_tabs_current = undef; local $rv; foreach my $t (@$tabs) { $rv .= "<<a href='$t->[2]'>". ($t->[0] eq $sel ? "<b>" : ""). $t->[1]. ($t->[0] eq $sel ? "</b>" : ""). "</a>>\n"; } $rv .= "<br>\n"; $rv .= &ui_hidden($name, $sel)."\n"; $main::current_selected_tab{$name} = $sel; return $rv; } } # Doesn't need to return anything for text-mode tabs sub theme_ui_tabs_end { if ($theme_ui_tabs_current) { # Compose email form .. so do nothing return ""; } elsif (&theme_use_iui()) { # Close big div for whole tab set return "</div>\n"; } else { return ""; } } # When in text mode, suppress output unless the named tab is selected sub theme_ui_tabs_start_tab { local ($name, $tab) = @_; if ($theme_ui_tabs_current) { # In mode where all tabs are shown, for composing email local ($t) = grep { $_->[0] eq $tab } @$theme_ui_tabs_current; #print "<b>$t->[1]</b>:\n"; } elsif (&theme_use_iui()) { # Outputting the tab, but with CSS for hiding local $defclass = $tab eq $main::ui_tabs_selected ? "tabVisible" : "tabHidden"; return "<div id='div_$tab' class='$defclass'>\n"; } elsif ($main::current_selected_tab{$name} ne $tab) { open(NULLFILE, ">$null_file"); $main::suppressing_tab = select(NULLFILE); } return ""; } sub theme_ui_tabs_start_tabletab { return &theme_ui_tabs_start_tab(@_); } # If we are currently suppressing, stop it sub theme_ui_tabs_end_tab { if ($theme_ui_tabs_current) { # End of tab in mode where we are showing all return "<br>\n"; } elsif (&theme_use_iui()) { # Close the tab, but with CSS for hiding return "</div>\n"; } elsif ($main::suppressing_tab) { # Stop suppressing output select($main::suppressing_tab); $main::suppressing_tab = undef; } return ""; } sub theme_ui_tabs_end_tabletab { return &theme_ui_tabs_end_tab(@_); } # Generate a simple list instead of a tab of icons sub theme_icons_table { local ($links, $titles, $icons, $cols, $href, $w, $h, $befores, $afters) = @_; local $i; print "<ul>\n"; for($i=0; $i<@$links; $i++) { print "<li class='iconList'>"; print $befores->[$i]; if ($links->[$i]) { print "<a href='$links->[$i]' $href class='iconLink'>$titles->[$i]</a>"; } else { print $titles->[$i]; } print $afters->[$i]; if (!&theme_use_iui()) { print "<br>\n"; } print "</li>\n"; } print "</ul>\n"; } # Doesn't bother with a grid, just put everything in one column # (for most devices) or two columns (for iPhone) sub theme_ui_grid_table { local ($elements, $cols, $width, $tds, $tabletags, $title) = @_; return "" if (!@$elements); if (&theme_use_iui()) { # Two-column grid, if narrow enough .. otherwise, one my $maxlen; foreach my $e (@$elements) { my $he = $e; $he =~ s/<[^>]*>//g; $maxlen = length($he) if (length($he) > $maxlen); } $cols = $maxlen > 30 ? 1 : 2; # Styled title my $rv; if (defined($title)) { $rv .= "<div class='webminGridBorder'>\n"; $rv .= "<div class='webminGridHeader'>$title</div>\n"; } else { $rv .= "<div class='webminGrid'>\n"; } # Grid body as a table $rv .= "<div class='webminGridBody'>\n"; $rv .= "<table".($width ? " width=$width%" : ""). ($tabletags ? " ".$tabletags : "").">\n"; my $i; for($i=0; $i<@$elements; $i++) { $rv .= "<tr>" if ($i%$cols == 0); $rv .= "<td width=25% valign=top>".$elements->[$i]."</td>\n"; $rv .= "</tr>" if ($i%$cols == $cols-1); } if ($i%$cols) { while($i%$cols) { $rv .= "<td width=25%></td>\n"; $i++; } $rv .= "</tr>\n"; } $rv .= "</table></div></div>\n"; return $rv; } else { # Just in one column local $rv = "<!--grid-->"; $rv .= "<b>$title</b><br>\n" if ($title); for(my $i=0; $i<@$elements; $i++) { $rv .= $elements->[$i]."<br>\n"; } return $rv; } } sub theme_print_iui_head { if (&theme_use_iui()) { # CSS and Javascript headers for IUI print "<meta name='viewport' content='width=320; ". "initial-scale=1.0; maximum-scale=1.0; user-scalable=0;'/>\n"; print "<style type='text/css' media='screen'>". "\@import '$gconfig{'webprefix'}/unauthenticated/iui/iui.css';". "</style>\n"; print "<script type='application/x-javascript' ". "src='$gconfig{'webprefix'}/unauthenticated/iui/iui.js'>". "</script>\n"; print "<link rel='apple-touch-icon' ". "href='$gconfig{'webprefix'}/unauthenticated/iphone-icon.png'>\n"; } } sub theme_header { print "<!doctype html public \"-//W3C//DTD HTML 3.2 Final//EN\">\n"; print "<html>\n"; local $os_type = $gconfig{'real_os_type'} || $gconfig{'os_type'}; local $os_version = $gconfig{'real_os_version'} || $gconfig{'os_version'}; local %module_info = get_module_info(get_module_name()); # Head section with title print "<head>\n"; if ($charset) { print "<meta http-equiv=\"Content-Type\" ", "content=\"text/html; Charset=$charset\">\n"; } &theme_print_iui_head(); if (@_ > 0) { # Output page title local $title = $_[0]; if ($gconfig{'showlogin'} && $remote_user) { $title = $remote_user." : ".$title; } print "<title>$title</title>\n"; print $_[7] if ($_[7]); } print "</head>\n"; # Start of the body local $bgcolor = "ffffff"; local $link = "0000ee"; local $text = "000000"; local $dir = $current_lang_info->{'dir'} ? "dir=\"$current_lang_info->{'dir'}\"" : ""; if (&theme_use_iui()) { print "<body $dir $_[8]>\n"; } else { print "<body bgcolor=#$bgcolor link=#$link vlink=#$link ". "text=#$text $dir $_[8]>\n"; } local $hostname = &get_display_hostname(); local $version = &get_webmin_version(); # These get used by the footer function $theme_iui_toolbar_title = undef; $theme_iui_toolbar_index = undef; $theme_iui_toolbar_button = undef; if (@_ > 1 && &theme_use_iui()) { # For IUI # Save entries for toolbar, for rendering in footer $theme_iui_toolbar_title = $_[0]; if (!$_[4] && !$tconfig{'nomoduleindex'} && get_module_name() ne "virtual-server" && get_module_name() ne "server-manager" && get_module_name() ne "mailbox") { # Module index local $idx = $module_info{'index_link'}; local $mi = $module_index_link || "/".get_module_name()."/$idx"; local $mt = $module_index_name || $text{'header_module'}; $theme_iui_toolbar_index = $mi; } if (ref($_[2]) eq "ARRAY" && !$ENV{'ANONYMOUS_USER'} && !$tconfig{'nohelp'}) { # Help in other module $theme_iui_toolbar_button = [ "/help.cgi/$_[2]->[0]/$_[2]->[1]", "Help" ]; } elsif (defined($_[2]) && !$ENV{'ANONYMOUS_USER'} && !$tconfig{'nohelp'}) { # Page help $theme_iui_toolbar_button = [ "/help.cgi/".get_module_name()."/$_[2]", "Help" ]; } if ($_[3]) { # Module Config local %access = &get_module_acl(); if (!$access{'noconfig'} && !$config{'noprefs'}) { local $cprog = $user_module_config_directory ? "uconfig.cgi" : "config.cgi"; local $cname = $cprog eq "uconfig.cgi" ? "Prefs" : "Config"; $theme_iui_toolbar_button = [ "/$cprog?".get_module_name(), $cname ]; } } # Open default div for page text if (!$main::theme_iui_no_default_div) { print "<div class='panel' selected='true' title='$_[0]'>\n"; } # Below and right-side links if ($_[6] || $_[9]) { local @linksr = split(/<br>\s*/, $_[6]); print "<div class=linksbar>\n"; if ($_[9]) { print "<h1>$_[9]</h1>\n"; } if (@linksr) { print "<table width=100%><tr>\n"; foreach my $l (@linksr) { print "<td class=linksrow>$l</td>\n"; } print "</tr></table>\n"; } print "</div>\n"; } } else { # For other mobile browsers # Show the title print "<center><b>$_[0]</b>"; print "<br>$_[9]\n" if ($_[9]); print "</center>\n"; # Work out links for top local @links; if ($ENV{'HTTP_WEBMIN_SERVERS'} && !$tconfig{'framed'}) { push(@links, "<a href='$ENV{'HTTP_WEBMIN_SERVERS'}'>". "$text{'header_servers'}</a>"); } if (!$_[5] && !$tconfig{'noindex'} && get_module_name() ne "virtual-server" && get_module_name() ne "server-manager" && get_module_name() ne "mailbox") { # Logout or switch user local @avail = &get_available_module_infos(1); local $nolo = $ENV{'ANONYMOUS_USER'} || $ENV{'SSL_USER'} || $ENV{'LOCAL_USER'} || $ENV{'HTTP_USER_AGENT'} =~ /webmin/i; if ($gconfig{'gotoone'} && $main::session_id && @avail == 1 && !$nolo) { push(@links, "<a href='$gconfig{'webprefix'}/session_login.cgi?logout=1'>$text{'main_logout'}</a>"); } elsif ($gconfig{'gotoone'} && @avail == 1 && !$nolo) { push(@links, "<a href=$gconfig{'webprefix'}/switch_user.cgi>$text{'main_switch'}</a>"); } elsif (!$gconfig{'gotoone'} || @avail > 1) { push(@links, "<a href='$gconfig{'webprefix'}/?cat=$module_info{'category'}'>$text{'header_webmin'}</a>"); } } if (!$_[4] && !$tconfig{'nomoduleindex'} && get_module_name() ne "virtual-server" && get_module_name() ne "server-manager" && get_module_name() ne "mailbox") { # Module index local $idx = $module_info{'index_link'}; local $mi = $module_index_link || "/".get_module_name()."/$idx"; local $mt = $module_index_name || $text{'header_module'}; push(@links, "<a href=\"$gconfig{'webprefix'}$mi\">$mt</a>"); } if (ref($_[2]) eq "ARRAY" && !$ENV{'ANONYMOUS_USER'} && !$tconfig{'nohelp'}) { # Help in other module push(@links, &hlink($text{'header_help'}, $_[2]->[0], $_[2]->[1])); } elsif (defined($_[2]) && !$ENV{'ANONYMOUS_USER'} && !$tconfig{'nohelp'}) { # Page help push(@links, &hlink($text{'header_help'}, $_[2])); } if ($_[3]) { # Module Config local %access = &get_module_acl(); if (!$access{'noconfig'} && !$config{'noprefs'}) { local $cprog = $user_module_config_directory ? "uconfig.cgi" : "config.cgi"; push(@links, "<a href=\"$gconfig{'webprefix'}/$cprog?". get_module_name()."\">$text{'header_config'}</a>"); } } # Print all links as a list push(@links, split(/<br>/, $_[6])); if (@links) { if (!defined(&ui_links_row)) { do '../ui-lib.pl'; } print &ui_links_row(\@links),"<p>\n"; } } } sub theme_post_init_config { if (get_module_name() eq "virtual-server") { # Don't show quotas on Virtualmin menu $config{'show_quotas'} = 0; } if (&theme_use_iui()) { # Don't limit text box sizes on IUI $tconfig{'maxboxwidth'} = undef; $tconfig{'maxareawidth'} = undef; } } # Output text-only selector sub theme_ui_radio_selector { local ($opts, $name, $sel) = @_; foreach my $o (@$opts) { $rv .= &ui_oneradio($name, $o->[0], $o->[1], $sel eq $o->[0])."<br>\n"; $rv .= $o->[2]; } return $rv; } sub theme_ui_buttons_start { return ""; } sub theme_ui_buttons_end { return ""; } sub theme_ui_buttons_row { local ($script, $label, $desc, $hiddens, $after, $before) = @_; return "<form action=$script>\n". $hiddens. ($before ? $before." " : ""). &ui_submit($label).($after ? " ".$after : "")."<br>\n". $desc."<p>\n". "</form>\n"; } sub theme_ui_buttons_hr { local ($title) = @_; local $rv; $rv .= "<b>$title</b><br>\n" if ($title); $rv .= "<hr>\n"; return $rv; } # theme_ui_opt_textbox(name, value, size, option1, [option2], [disabled?], # [&extra-fields], [max]) # Returns HTML for a text field that is optional sub theme_ui_opt_textbox { local ($name, $value, $size, $opt1, $opt2, $dis, $extra, $max) = @_; local $rv; $size = &ui_max_text_width($size); $rv .= &ui_radio($name."_def", $value eq '' ? 1 : 0, [ [ 1, $opt1 ], [ 0, $opt2 || " " ] ], $dis)."\n"; $rv .= "<input name=\""."e_escape($name)."\" ". "size=$size value=\""."e_escape($value)."\" ". ($dis ? "disabled=true" : ""). ($max ? " maxlength=$max" : "").">\n"; return $rv; } # theme_virtualmin_ui_rating_selector(name, value, max, cgi) sub theme_virtualmin_ui_rating_selector { local ($name, $value, $max, $cgi) = @_; local $rv; for($i=1; $i<=$max; $i++) { local $char = $i <= $value ? "X" : "-"; if ($cgi) { local $cgiv = $cgi; $cgiv .= ($cgi =~ /\?/ ? "&" : "?"); $cgiv .= $name."=".$i; $rv .= "<a href='$cgiv' id=$name$i>$char</a>"; } else { $rv .= $char; } } return $rv; } sub theme_ui_submit { local ($label, $name, $dis, $tags) = @_; local $style = &theme_use_iui() ? "style='font-size: 12px'" : "style='font-size: 8px'"; return "<input type=submit". ($name ne '' ? " name=\""."e_escape($name)."\"" : ""). " value=\""."e_escape($label)."\"". ($dis ? " disabled=true" : ""). ($tags ? " ".$tags : "")." ".$style.">\n"; } # On the mail sending page, use a text box for addresses to save space sub theme_ui_textarea { local ($name, $value, $rows, $cols, $wrap, $dis, $tags) = @_; if (get_module_name() eq "mailbox" && $0 =~ /reply_mail.cgi/ && ($name eq "to" || $name eq "cc" || $name eq "bcc")) { $value =~ s/\n/ /g; return &ui_textbox($name, $value, $cols, $dis, undef, $tags); } else { $cols = &ui_max_text_width($cols, 1); return "<textarea name=\""."e_escape($name)."\" ". "rows=$rows cols=$cols".($wrap ? " wrap=$wrap" : ""). ($dis ? " disabled=true" : ""). ($tags ? " $tags" : "").">". &html_escape($value). "</textarea>"; } } # Popup buttons don't work sub theme_modules_chooser_button { return undef; } sub theme_file_chooser_button { return undef; } sub theme_user_chooser_button { return undef; } sub theme_group_chooser_button { return undef; } sub theme_date_chooser_button { return undef; } sub theme_address_button { return undef; } # Function overrides for Read Mail usermin module sub theme_left_right_align { return $_[0]." ".$_[1]; } sub theme_show_arrows { local %ttext = &load_language($current_theme); local $folder = &get_module_variable('$folder'); local $mail = &get_module_variable('$mail'); if (!@sub) { # Get next and previous emails, where they exist local $c = &mailbox::mailbox_folder_size($folder, 1); local $prv = $mail->{'sortidx'} == 0 ? 0 : $mail->{'sortidx'}-1; local $nxt = $mail->{'sortidx'} == $c-1 ? $c-1 : $mail->{'sortidx'}+1; local @beside = &mailbox::mailbox_list_mails_sorted($prv, $nxt, $folder, 1); if ($mail->{'sortidx'} != 0) { local $mailprv = $beside[$prv]; print "<a href='view_mail.cgi?id=",&urlize($mailprv->{'id'}), "&folder=$in{'folder'}&start=$in{'start'}'>", "<$ttext{'mail_next'}</a>"; } else { print "<$ttext{'mail_next'}\n"; } print " | ",&text('view_desc', $mail->{'sortidx'}+1, $folder->{'name'})," | "; if ($mail->{'sortidx'} < $c-1) { local $mailnxt = $beside[$nxt]; print "<a href='view_mail.cgi?id=",&urlize($mailnxt->{'id'}), "&folder=$in{'folder'}&start=$in{'start'}'>", "$ttext{'mail_prev'}></a>"; } else { print "$ttext{'mail_prev'}>\n"; } } else { print $text{'view_sub'},"\n"; } print "<br>\n"; } sub theme_show_buttons { # Show links for common actions on a single mail local %ttext = &load_language($current_theme); local @bacts; local $url = "reply_mail.cgi?id=".&urlize($in{'id'}). "&folder=".&urlize($in{'folder'}). "&body=".&urlize($in{'body'}). "&start=".&urlize($in{'start'}); foreach my $s (@sub) { $url .= "&sub=$s"; } if ($folder->{'sent'} || $folder->{'drafts'}) { push(@bacts, "<a href='$url&enew=1'>$mailbox::text{'view_enew'}</a>"); push(@bacts, "<a href='$url&ereply=1'>$mailbox::text{'view_reply'}</a>"); push(@bacts, "<a href='$url&erall=1'>$mailbox::text{'view_reply2'}</a>"); } else { push(@bacts, "<a href='$url&reply=1'>$mailbox::text{'view_reply'}</a>"); push(@bacts, "<a href='$url&rall=1'>$mailbox::text{'view_reply2'}</a>"); } push(@bacts, "<a href='$url&new=1'>$mailbox::text{'mail_compose'}</a>"); push(@bacts, "<a href='$url&forward=1'>$mailbox::text{'view_forward'}</a>"); if (!$_[1]) { # Show mark buttons, except for current mode if (!$folder->{'sent'} && !$folder->{'drafts'}) { $m = &mailbox::get_mail_read($folder, $mail); foreach $i (0 .. 2) { if ($m != $i) { push(@bacts, "<a href='$url&markas$i=1'>". $ttext{'mail_markas'.$i}."</a>"); } } } } if (!$_[1]) { # Show spam and/or ham report buttons if (&mailbox::can_report_spam($folder) && $userconfig{'spam_buttons'} =~ /mail/) { if ($userconfig{'spam_del'}) { push(@bacts, "<a href='$url&razor=1'>$mailbox::text{'view_razordel'}</a>"); } else { push(@bacts, "<a href='$url&razor=1'>$mailbox::text{'view_razor'}</a>"); } } if (&mailbox::can_report_ham($folder) && $userconfig{'ham_buttons'} =~ /mail/) { if ($userconfig{'white_move'} && $folder->{'spam'}) { push(@bacts, "<a href='$url&white=1'>$mailbox::text{'view_whitemove'}</a>"); } else { push(@bacts, "<a href='$url&white=1'>$mailbox::text{'view_white'}</a>"); } if ($userconfig{'ham_move'} && $folder->{'spam'}) { push(@bacts, "<a href='$url&ham=1'>$mailbox::text{'view_hammove'}</a>"); } else { push(@bacts, "<a href='$url&ham=1'>$mailbox::text{'view_ham'}</a>"); } } } if (@folders > 1) { push(@bacts, "<a href='action_mail.cgi?ok1=1&action1=move&folder=$in{'folder'}&start=$in{'start'}&d=$in{'id'}'>$ttext{'view_move'}</a>"); push(@bacts, "<a href='action_mail.cgi?ok1=1&action1=copy&folder=$in{'folder'}&start=$in{'start'}&d=$in{'id'}'>$ttext{'view_copy'}</a>"); } if (!@subs) { push(@bacts, "<a href='$url&delete=1'>$mailbox::text{'view_delete'}</a>"); } print "<b>$ttext{'view_actions'}</b> ", join(" | ", @bacts),"<br>\n"; } # XXX how can this work?? if (get_module_name() eq "mailbox" && $0 =~ /((view|reply)_mail.cgi|search_form.cgi)/) { # UI overrides for viewing email $mailbox::{'left_right_align'} = \&theme_left_right_align; $mailbox::{'search_link'} = sub { return "" }; $mailbox::{'show_arrows'} = \&theme_show_arrows; $mailbox::{'show_buttons'} = \&theme_show_buttons; local %ttext = &load_language($current_theme); $mailbox::text{'view_noheaders'} = $ttext{'view_noheaders'}; $mailbox::text{'view_allheaders'} = $ttext{'view_allheaders'}; $mailbox::text{'view_raw'} = $ttext{'view_raw'}; $mailbox::text{'sform_and'} = $ttext{'search_and'}; $mailbox::text{'sform_or'} = $ttext{'search_or'}; # To supress HTML compose links $mailbox::text{'reply_html0'} = undef; $mailbox::text{'reply_html1'} = undef; # Never use HTML editor $mailbox::userconfig{'head_html'} = 0; $mailbox::userconfig{'html_edit'} = 0; $mailbox::userconfig{'view_html'} = 1; # Only show one set of send buttons $mailbox::userconfig{'send_buttons'} = 0; } sub theme_virtualmin_ui_show_cron_time { local ($name, $job, $offmsg) = @_; &foreign_require("cron", "cron-lib.pl"); local $rv; local $mode = !$job ? 0 : $job->{'special'} ? 1 : 2; local $hidden = $mode == 2 ? join(" ", $job->{'mins'}, $job->{'hours'}, $job->{'days'}, $job->{'months'}, $job->{'weekdays'}) : ""; return &ui_radio_table($name, $mode, [ $offmsg ? ( [ 0, $offmsg ] ) : ( ), [ 1, $virtual_server::text{'cron_special'}, &ui_select($name."_special", $job->{'special'}, [ map { [ $_, $cron::text{'edit_special_'.$_} ] } ('hourly', 'daily', 'weekly', 'monthly', 'yearly') ]) ], [ 2, $virtual_server::text{'cron_cron'}, &ui_textbox($name."_hidden", $hidden) ], ]); } sub theme_use_iui { return $ENV{'HTTP_USER_AGENT'} =~ /iPhone|iPod|iPad|Android|Pre|Pixi\/|Nintendo/; } sub theme_popup_header { print "<!doctype html public \"-//W3C//DTD HTML 3.2 Final//EN\">\n"; print "<html>\n"; print "<head>\n"; &theme_print_iui_head(); print "<title>$_[0]</title>\n"; print $_[1]; print "</head>\n"; local $bgcolor = defined($tconfig{'cs_page'}) ? $tconfig{'cs_page'} : defined($gconfig{'cs_page'}) ? $gconfig{'cs_page'} : "ffffff"; local $link = defined($tconfig{'cs_link'}) ? $tconfig{'cs_link'} : defined($gconfig{'cs_link'}) ? $gconfig{'cs_link'} : "0000ee"; local $text = defined($tconfig{'cs_text'}) ? $tconfig{'cs_text'} : defined($gconfig{'cs_text'}) ? $gconfig{'cs_text'} : "000000"; local $bgimage = defined($tconfig{'bgimage'}) ? "background=$tconfig{'bgimage'}" : ""; if (&theme_use_iui()) { print "<body $_[2]>\n"; print "<div class='toolbar'>\n"; print "<h1 id='pageTitle'>$_[0]</h1>\n"; print "<a id='backButton' class='button' href='#'></a>\n"; print "</div>\n"; if (!$main::theme_iui_no_default_div) { print "<div class='panel' selected='true' title='$_[0]'>\n"; } } else { print "<body id='popup' bgcolor=#$bgcolor link=#$link vlink=#$link ", "text=#$text $bgimage $tconfig{'inbody'} $_[2]>\n"; } } sub theme_popup_footer { if (&theme_use_iui() && !$main::theme_iui_no_default_div) { print "</div>\n"; } print "</body></html>\n"; } sub theme_hlink { local $mod = $_[2] ? $_[2] : get_module_name(); return "<a href='/help.cgi/$mod/$_[1]' target=_new ". "class='webminHelpLink'>$_[0]</a>"; } # Turn off javascript redirects unless we have IUI sub theme_js_redirect { my ($url, $window) = @_; if (&theme_use_iui()) { $window ||= "window"; return "<script>${window}.location = '". "e_escape($url)."';</script>\n"; } else { return ""; } } # theme_ui_multi_select(name, &values, &options, size, [add-if-missing], # [disabled?], [options-title, values-title], [width]) sub theme_ui_multi_select { local ($name, $values, $opts, $size, $missing, $dis, $opts_title, $vals_title, $width) = @_; if (&theme_use_iui()) { # For IUI, use checkboxes my $rv; my %already = map { $_->[0], $_ } @$values; if (!$main::theme_ui_multi_select_donejs++) { $rv .= &theme_ui_multi_select_javascript(); } local $qname = "e_escape($name); local $js = "onClick='multi_select_change(\"$qname\", form)'"; foreach my $o (@$opts) { $rv .= &ui_checkbox($name."_checkbox", $o->[0], $o->[1], $already{$o->[0]}, $js)."<br>\n"; delete($already{$o->[0]}); } foreach my $o (values %$already) { $rv .= &ui_checkbox($name."_checkbox", $o->[0], $o->[1], 1, $js)."<br>\n"; } $rv .= &ui_hidden($name, join("\n", map { $_->[0] } @$values)); return $rv; } else { # The Javascript left/right selector isn't supported, so don't even # try to use it. return &ui_textarea($name, join("\n", map { $_->[0] } @$values), $size, 30, "off", $dis); } } sub theme_ui_multi_select_javascript { return <<EOF; <script> function multi_select_change(name, f) { var v = [ ]; var vals = f.elements[name]; for(var i=0; i<f.elements.length; i++) { var e = f.elements[i]; if (e.name == name+"_checkbox" && e.checked) { v.push(e.value); } } vals.value = v.join("\\n"); } </script> EOF } # theme_ui_radio_table(name, selected, &rows) # Returns HTML for a table of radio buttons, each of which has a label and # some associated inputs to the right. sub theme_ui_radio_table { local ($name, $sel, $rows) = @_; return "" if (!@$rows); my $rv; foreach my $r (@$rows) { $rv .= "<b>".&ui_oneradio($name, $r->[0], $r->[1], $r->[0] eq $sel)."</b><br>\n"; if ($r->[2]) { $rv .= " ".$r->[2]."<br>\n"; } } return $rv; } 1;y~or5J={Eeu磝Qk ᯘG{?+]ן?wM3X^歌>{7پK>on\jy Rg/=fOroNVv~Y+ NGuÝHWyw[eQʨSb> >}Gmx[o[<{Ϯ_qFvM IENDB`