]> git.sur5r.net Git - bacula/bacula/commitdiff
ebl release file on sf Release-2.0.2
authorEric Bollengier <eric@eb.homelinux.org>
Wed, 7 Feb 2007 17:17:16 +0000 (17:17 +0000)
committerEric Bollengier <eric@eb.homelinux.org>
Wed, 7 Feb 2007 17:17:16 +0000 (17:17 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/tags/Release-2.0.2@4144 91ce42f0-d328-0410-95d8-f526ca767f89

192 files changed:
gui/bweb/COPYING [new file with mode: 0644]
gui/bweb/INSTALL [new file with mode: 0644]
gui/bweb/MANIFEST [new file with mode: 0644]
gui/bweb/Makefile.PL [new file with mode: 0644]
gui/bweb/ReleaseNotes [new file with mode: 0644]
gui/bweb/cgi/bconsole.pl [new file with mode: 0755]
gui/bweb/cgi/bfileview.pl [new file with mode: 0755]
gui/bweb/cgi/bgraph.pl [new file with mode: 0755]
gui/bweb/cgi/bweb.pl [new file with mode: 0755]
gui/bweb/html/A.png [new file with mode: 0644]
gui/bweb/html/E.png [new file with mode: 0644]
gui/bweb/html/R.png [new file with mode: 0644]
gui/bweb/html/T.png [new file with mode: 0644]
gui/bweb/html/W.png [new file with mode: 0644]
gui/bweb/html/add.png [new file with mode: 0644]
gui/bweb/html/apply.png [new file with mode: 0644]
gui/bweb/html/bweb.css [new file with mode: 0644]
gui/bweb/html/bweb.js [new file with mode: 0644]
gui/bweb/html/cancel.png [new file with mode: 0644]
gui/bweb/html/chart.png [new file with mode: 0644]
gui/bweb/html/client.png [new file with mode: 0644]
gui/bweb/html/colorscm.png [new file with mode: 0644]
gui/bweb/html/down.gif [new file with mode: 0755]
gui/bweb/html/edit.png [new file with mode: 0644]
gui/bweb/html/extern.png [new file with mode: 0644]
gui/bweb/html/f.png [new file with mode: 0644]
gui/bweb/html/favicon.ico [new file with mode: 0644]
gui/bweb/html/filename.png [new file with mode: 0644]
gui/bweb/html/first.gif [new file with mode: 0755]
gui/bweb/html/first.png [new file with mode: 0644]
gui/bweb/html/index.html [new file with mode: 0644]
gui/bweb/html/inflag0.png [new file with mode: 0644]
gui/bweb/html/inflag1.png [new file with mode: 0644]
gui/bweb/html/intern.png [new file with mode: 0644]
gui/bweb/html/kaiska.css [new file with mode: 0644]
gui/bweb/html/label.png [new file with mode: 0644]
gui/bweb/html/last.gif [new file with mode: 0755]
gui/bweb/html/last.png [new file with mode: 0644]
gui/bweb/html/lcorner.png [new file with mode: 0644]
gui/bweb/html/left.gif [new file with mode: 0755]
gui/bweb/html/left.png [new file with mode: 0644]
gui/bweb/html/load.png [new file with mode: 0644]
gui/bweb/html/lock.png [new file with mode: 0644]
gui/bweb/html/natcompare.js [new file with mode: 0755]
gui/bweb/html/next.png [new file with mode: 0644]
gui/bweb/html/nrs_table.js [new file with mode: 0755]
gui/bweb/html/pix.png [new file with mode: 0644]
gui/bweb/html/prev.png [new file with mode: 0644]
gui/bweb/html/prune.png [new file with mode: 0644]
gui/bweb/html/purge.png [new file with mode: 0644]
gui/bweb/html/rcorner.png [new file with mode: 0644]
gui/bweb/html/remove.png [new file with mode: 0644]
gui/bweb/html/right.gif [new file with mode: 0755]
gui/bweb/html/right.png [new file with mode: 0644]
gui/bweb/html/save.png [new file with mode: 0644]
gui/bweb/html/style.css [new file with mode: 0644]
gui/bweb/html/tape.png [new file with mode: 0644]
gui/bweb/html/unload.png [new file with mode: 0644]
gui/bweb/html/up.gif [new file with mode: 0755]
gui/bweb/html/update.png [new file with mode: 0644]
gui/bweb/html/zoom.png [new file with mode: 0644]
gui/bweb/install_bweb [new file with mode: 0755]
gui/bweb/lang/es/tpl/about.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/ach_add.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/ach_content.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/begin.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/change_location.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/client_job_status.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/client_list.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/command.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/config_edit.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/config_view.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/display_client_job.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/display_client_stats.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/display_form_job.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/display_form_media.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/display_job.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/display_job_zoom.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/display_location.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/display_log.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/display_media.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/display_media_zoom.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/display_pool.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/end.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/error.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/fileset_view.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/fv_file_attribs.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/general.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/graph.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/help_extern.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/help_extern_compute.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/help_intern.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/help_intern_compute.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/install.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/location_add.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/location_edit.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/move_media.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/run_job.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/run_job_mod.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/running_job.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/scheduled_job.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/stats.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/update_location.tpl [new file with mode: 0644]
gui/bweb/lang/es/tpl/update_media.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/about.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/ach_add.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/ach_content.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/begin.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/change_location.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/client_job_status.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/client_list.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/command.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/config_edit.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/config_view.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/display_client_job.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/display_client_stats.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/display_form_job.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/display_form_media.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/display_job.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/display_job_zoom.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/display_location.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/display_log.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/display_media.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/display_media_zoom.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/display_pool.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/end.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/error.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/fileset_view.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/fv_file_attribs.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/general.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/graph.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/help_extern.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/help_extern_compute.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/help_intern.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/help_intern_compute.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/location_add.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/location_edit.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/move_media.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/run_job.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/run_job_mod.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/running_job.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/scheduled_job.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/stats.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/update_location.tpl [new file with mode: 0644]
gui/bweb/lang/fr/tpl/update_media.tpl [new file with mode: 0644]
gui/bweb/lib/Bconsole.pm [new file with mode: 0644]
gui/bweb/lib/Bweb.pm [new file with mode: 0644]
gui/bweb/lib/CCircle.pm [new file with mode: 0644]
gui/bweb/script/bweb-postgresql.sql [new file with mode: 0644]
gui/bweb/script/bweb.conf [new file with mode: 0644]
gui/bweb/tpl/about.tpl [new file with mode: 0644]
gui/bweb/tpl/ach_add.tpl [new file with mode: 0644]
gui/bweb/tpl/ach_content.tpl [new file with mode: 0644]
gui/bweb/tpl/begin.tpl [new file with mode: 0644]
gui/bweb/tpl/change_location.tpl [new file with mode: 0644]
gui/bweb/tpl/client_job_status.tpl [new file with mode: 0644]
gui/bweb/tpl/client_list.tpl [new file with mode: 0644]
gui/bweb/tpl/command.tpl [new file with mode: 0644]
gui/bweb/tpl/config_edit.tpl [new file with mode: 0644]
gui/bweb/tpl/config_view.tpl [new file with mode: 0644]
gui/bweb/tpl/display_client_job.tpl [new file with mode: 0644]
gui/bweb/tpl/display_client_stats.tpl [new file with mode: 0644]
gui/bweb/tpl/display_form_job.tpl [new file with mode: 0644]
gui/bweb/tpl/display_form_media.tpl [new file with mode: 0644]
gui/bweb/tpl/display_job.tpl [new file with mode: 0644]
gui/bweb/tpl/display_job_zoom.tpl [new file with mode: 0644]
gui/bweb/tpl/display_location.tpl [new file with mode: 0644]
gui/bweb/tpl/display_log.tpl [new file with mode: 0644]
gui/bweb/tpl/display_media.tpl [new file with mode: 0644]
gui/bweb/tpl/display_media_zoom.tpl [new file with mode: 0644]
gui/bweb/tpl/display_pool.tpl [new file with mode: 0644]
gui/bweb/tpl/end.tpl [new file with mode: 0644]
gui/bweb/tpl/error.tpl [new file with mode: 0644]
gui/bweb/tpl/fileset_view.tpl [new file with mode: 0644]
gui/bweb/tpl/fv_file_attribs.tpl [new file with mode: 0644]
gui/bweb/tpl/general.tpl [new file with mode: 0644]
gui/bweb/tpl/graph.tpl [new file with mode: 0644]
gui/bweb/tpl/help_extern.tpl [new file with mode: 0644]
gui/bweb/tpl/help_extern_compute.tpl [new file with mode: 0644]
gui/bweb/tpl/help_intern.tpl [new file with mode: 0644]
gui/bweb/tpl/help_intern_compute.tpl [new file with mode: 0644]
gui/bweb/tpl/install.tpl [new file with mode: 0644]
gui/bweb/tpl/location_add.tpl [new file with mode: 0644]
gui/bweb/tpl/location_edit.tpl [new file with mode: 0644]
gui/bweb/tpl/move_media.tpl [new file with mode: 0644]
gui/bweb/tpl/run_job.tpl [new file with mode: 0644]
gui/bweb/tpl/run_job_mod.tpl [new file with mode: 0644]
gui/bweb/tpl/running_job.tpl [new file with mode: 0644]
gui/bweb/tpl/scheduled_job.tpl [new file with mode: 0644]
gui/bweb/tpl/stats.tpl [new file with mode: 0644]
gui/bweb/tpl/update_location.tpl [new file with mode: 0644]
gui/bweb/tpl/update_media.tpl [new file with mode: 0644]

diff --git a/gui/bweb/COPYING b/gui/bweb/COPYING
new file mode 100644 (file)
index 0000000..960fe74
--- /dev/null
@@ -0,0 +1,280 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
diff --git a/gui/bweb/INSTALL b/gui/bweb/INSTALL
new file mode 100644 (file)
index 0000000..c44494c
--- /dev/null
@@ -0,0 +1,280 @@
+################################################################
+#               INSTALL NOTES                                  #
+################################################################
+
+Bweb works well with 1.39 release or later.
+
+1) install Perl lib
+2) copy your files
+3) initialize your configuration file
+4) do some sql stuff (for postgresql users)
+5) use the -n option on bconsole so that it works with Expect
+6) get bacula log more useful
+7) bweb limitation
+8) using sudo with autochanger
+9) using bfileview.pl
+10) accessing to bweb
+
+################ FILE COPY #####################################
+ # you must get bweb cvs files
+ cvs -d:pserver:anonymous@bacula.cvs.sourceforge.net:/cvsroot/bacula login 
+ cvs -z3 -d:pserver:anonymous@bacula.cvs.sourceforge.net:/cvsroot/bacula co -P gui
+ cd gui
+
+ # or get them from the released tar files or from the apt or rpms.
+
+ #
+ # Once you have the gui directory loaded, follow the instructions below
+ #  or edit the environment variables in the file install_bweb
+ #  then execute it. install_web does everything to the next
+ #  set of #######'s.
+ #
+
+ # first, copy the bweb Perl library into your PERL5 INC path
+ perl Makefile.PL
+ make install
+ # or
+ install -m 644 -o root -g root  bweb/lib/*.pm /usr/share/perl5
+
+ # copy the bweb perl program to your cgi location
+ mkdir -m 755 /usr/lib/cgi-bin/bweb
+ install -m 755 -o root -g root  bweb/cgi/*.pl /usr/lib/cgi-bin/bweb
+
+ # get a config file
+ mkdir -m 755 /etc/bacula
+ chown root:bacula /etc/bacula
+ echo '$VAR1 = { template_dir => "/usr/share/bweb/tpl" };' > /etc/bacula/bweb.conf
+ chown www-data /etc/bacula/bweb.conf
+
+ # copy the bweb template file
+ mkdir -p /usr/share/bweb/tpl
+ install -m 644 -o root -g root  bweb/tpl/*.tpl /usr/share/bweb/tpl
+
+ # copy the bweb graphics elements (bweb elements must reside in /bweb)
+ mkdir /var/www/bweb
+ install -m 644 -o root -g root  bweb/html/*.{js,png,css,gif,ico,html} /var/www/bweb
+
+ # done !
+
+ WARNING : Your www-data (or wwwrun on SuSE) user must be able to execute bconsole and able 
+           to read the bconsole.conf file!
+           You can create an bconsole group for that.
+
+################ USE FRENCH VERSION ############################
+
+Simply use lang/fr/tpl/*.tpl files instead of tpl/*.tpl
+
+################ INSTALL PERL LIBRARY ##########################
+
+ - perl modules
+    - DBI (with mysql or postgresql support DBD::Pg and DBD::mysql)
+    - GD::Graph
+    - GD
+    - HTML::Template
+    - CGI
+    - Expect
+    - Time::ParseDate
+
+ You can install perl modules with CPAN
+ perl -e shell -MCPAN
+  > install Expect
+
+ Or use your distribution
+ apt-get install libgd-graph-perl libhtml-template-perl libexpect-perl
+ apt-get install libdbd-mysql-perl libdbd-pg-perl libdbi-perl libtime-modules-perl
+
+ Note: the best way to test if you have all the dependencies
+ fullfilled for Perl is to:
+  
+    cd /var/www/cgi-bin/bweb
+    ./bweb.pl 
+
+ you might also want to try:
+
+    ./bgraph.pl 
+
+ To make sure the graphing modules are loaded.  However, running it
+ will spray binary graphics data on your terminal.  Otherwise, you will
+ get an error.
+
+ That should show you if any of the pre-requisites are missing.
+ On SuSE 10.2, I was able to load all the appropriate modules via rpms,
+  with the exception of Expect and Time::ParseDate, which I loaded manually
+  using perl.
+
+  If you experience problems, always consult the Apache error_log
+  file.
+
+################ APACHE CONFIGURATION ##########################
+
+It could be a good idea to protect your bweb installation (optional).
+
+Put this in your httpd.conf, and add user with htpasswd
+
+<Directory /usr/lib/cgi-bin/bweb>
+        Options ExecCGI -MultiViews +SymLinksIfOwnerMatch
+        AuthType Basic
+        AuthName MyPrivateFile
+        AuthUserFile /etc/apache/htpasswd
+        AllowOverride None
+        Require valid-user
+</Directory>
+
+On SuSE 10.2, the following in /etc/apache2/default-server.conf works. 
+However, it is not secure:
+
+Directory "/srv/www/cgi-bin/bweb">
+ AllowOverride None
+ Options +ExecCGI -Includes
+ Order allow,deny
+ Allow from all
+</Directory>
+
+
+################ CONFIGURATION #################################
+
+Note, this is automatically installed by the install_bweb script.
+
+/etc/bacula/bweb.conf looks like : (you can edit it inside bweb)
+$VAR1 = bless( {
+  'graph_font' => '/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf',
+  'name' => undef,
+  'config_file' => '/etc/bacula/bweb.conf',
+  'bconsole' => '/usr/sbin/bconsole -n -c /etc/bacula/bconsole.conf',
+  'ach_list' => {
+     'S1_L80' => bless( {
+         'info' => {
+                     'drive' => 0,
+                     'io' => 0,
+                     'slot' => 0
+                   },
+         'name' => 'S1_L80',
+         'bweb' => undef,
+         'device' => '/dev/changer',
+         'drive' => [],
+         'debug' => 0,
+         'label' => {},
+         'precmd' => 'sudo',
+         'io' => [],
+         'mtxcmd' => '/usr/sbin/mtx',
+         'drive_name' => [
+                           'S1_L80_SDLT0',
+                           'S1_L80_SDLT1'
+                         ],
+         'slot' => []
+       }, 'Bweb::Autochanger' )
+   },
+  'password' => 'xxx',
+  'template_dir' => '/usr/share/bweb/tpl',
+  'dbi' => 'DBI:mysql:database=bacula',
+  'error' => '',
+  'debug' => 0,
+  'user' => 'bacula',
+  'email_media' => 'eric@localhost'
+}, 'Bweb::Config' );
+
+
+################ BRESTORE ######################################
+
+If you want to use brestore with bweb, you must associate a mime type
+text/brestore with your brestore.pl, and you must install brestore.
+See gui/brestore/README for instructions on installing brestore.pl.
+
+################ POSTGRESQL NOTES ##############################
+
+If you want to use PostgreSQL instead of MySQL, you must add
+a function to the PostgreSQL Bacula database to get Bweb to work.
+
+psql -U bacula bacula < script/bweb-postgresql.sql
+
+Tips: PL must be enable in your cluster, you can do this with postgres user
+postgres:~$ echo 'CREATE PROCEDURAL LANGUAGE plpgsql;' | psql bacula 
+
+################ BCONSOLE NOTES ################################
+
+You must use bconsole without conio/readline support. For that, use
+the bconsole -n option. This is done automatically with the standard
+configuration file.  In addition, please ensure that the binary
+bconsole file can be executed by your web server. It is normally
+located in /usr/bin/bconsole (or some such file), and must have
+modes 755 or it will not be executable by your web server.  The
+normal Bacula installation usually sets mode 750.
+
+################ BACULA LOG ####################################
+
+If you want Bweb to be able to show listings of the Job output,
+you must add a "catalog = all, !skipped, !saved" to your
+messages resource in bacula-dir.conf and restart your Bacula 
+server.  This is shown below:
+
+Messages {
+  Name = Standard
+
+  operator = root@localhost = mount
+  console = all, !skipped, !saved
+  append = "/tmp/bacula/var/bacula/working/log" = all, !skipped
+
+  catalog = all, !skipped, !saved
+}
+
+
+################ BWEB LIMITATION ###############################
+
+To get bweb working, you must follow these rules
+ - Media, Storage and Pool must have [A-Za-z_0-9\.-]+ (no space)
+ - AutoChanger name must be same as Device and Location name in bacula
+
+################ SUDO CONFIGURATION ############################
+
+If you use sudo, put this on you /etc/sudoers
+
+www-data ALL = (root) NOPASSWD: /usr/sbin/mtx -f /dev/changer transfer *
+www-data ALL = (root) NOPASSWD: /usr/sbin/mtx -f /dev/changer status
+www-data ALL = (root) NOPASSWD: /usr/sbin/mtx -f /dev/changer load *
+www-data ALL = (root) NOPASSWD: /usr/sbin/mtx -f /dev/changer unload *
+
+################ BFILEVIEW SETUP ###############################
+
+At this time, bfileview works only with PostgreSQL.
+
+Alias /bweb/fv /var/spool/bweb
+<Directory "/var/spool/bweb">
+    Options None
+    AllowOverride AuthConfig
+    Order allow,deny
+    Allow from all
+</Directory>
+
+mkdir /var/spool/bweb
+chmod 700 /var/spool/bweb
+chown www-data /var/spool/bweb
+
+You have to remove "<!-- Remove this to activate bfileview" and "-->" from
+tpl/display_job_zoom.tpl.
+
+You must use brestore.pl -b to initialize the database, and
+you can use bfileview.pl mode=batch jobid=xxx where=/ to compute tree size.
+
+At this time, it's a good idea to schedule brestore.pl -b after your 
+BackupCatalog job.
+
+Job {
+  Name = "BackupCatalog"
+  ...
+  # This creates an ASCII copy of the catalog
+  RunBeforeJob = "/opt/bacula/etc/make_catalog_backup bacula bacula Pei0ahm9"
+  # This deletes the copy of the catalog
+  RunAfterJob  = "/opt/bacula/etc/delete_catalog_backup"
+  RunAfterJob  = "/usr/local/bin/brestore.pl -b"
+}
+
+To upgrade from an old installation, you can use :
+ALTER TABLE brestore_pathvisibility ADD Size int8;
+ALTER TABLE brestore_pathvisibility ADD Files int4;
+
+################ ACCESSING TO BWEB ###############################
+
+Now, you are able to launch firefox/mozilla and go on
+http://your-server/bweb
+
+Enjoy !
diff --git a/gui/bweb/MANIFEST b/gui/bweb/MANIFEST
new file mode 100644 (file)
index 0000000..8c0eecd
--- /dev/null
@@ -0,0 +1,7 @@
+lib/Bweb.pm
+lib/Bconsole.pm
+lib/CCircle.pm
+Makefile.PL
+INSTALL
+COPYING
+MANIFEST
diff --git a/gui/bweb/Makefile.PL b/gui/bweb/Makefile.PL
new file mode 100644 (file)
index 0000000..45833d1
--- /dev/null
@@ -0,0 +1,26 @@
+use Test::More tests => 7;
+
+require_ok('DBI');
+require_ok('GD::Graph');
+require_ok('GD');
+require_ok('HTML::Template');
+require_ok('CGI');
+require_ok('Expect');
+require_ok('Time::ParseDate');
+
+
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+ ABSTRACT => "An other Bacula WEB interface",
+ AUTHOR   => "Eric Bollengier <eric@eb.homelinux.org>",
+ NAME     => 'Bweb',
+ VERSION  => "lib/Bweb.pm",
+
+ #INST_BIN => "cgi",
+ # setup your cgi installation
+ # debian      : /usr/lib/cgi-bin/bweb
+ # redhat/suse : /var/www/cgi-bin/bweb
+ # 
+ #INSTALLSITEBIN => "/usr/lib/cgi-bin/bweb",
+);
diff --git a/gui/bweb/ReleaseNotes b/gui/bweb/ReleaseNotes
new file mode 100644 (file)
index 0000000..82c2a09
--- /dev/null
@@ -0,0 +1,108 @@
+          Release Notes for bweb 2.0
+
+2007/01/25
+ - Add spanish translation, thanks to Santiago Alberch <caesarneron@gmail.com>
+
+2007/01/15
+ - fix do_update_media timeout bug
+
+2007/01/09
+ - fix stats bug on main page
+
+2007/01/01
+ - Add an index.html page on /bweb
+
+2006/12/31
+ - Move /etc/bweb/config to /etc/bacula/bweb.conf
+
+2006/12/29
+ - Add graphical backup view. See INSTALL to enable it. It's usefull
+   for tuning backup.
+   NOTES : 
+    - You must use brestore -b to initialise database after BackupCatalog job
+    - If you have an old installation, you must alter your schema (see INSTALL)
+
+2006/12/14
+ - Add pool filter to job form
+
+2006/12/12
+ - Add More options button to run_job and Start Date field
+
+2006/12/09
+ - Update Copyright
+
+2006/12/05
+ - Add html form filter to media view
+
+2006/12/04
+ - Add mediatype filter to pool view
+
+2006/11/18
+ - Add system log to job log (JobId = 0)
+
+2006/11/18
+ - Add debian package  
+ - Add cgi/bconsole.pl and BwebConsole package to keep bconsole installation and
+   scp usage on admin workstation.
+
+2006/11/16
+ - Add Comment and RecyclePool to Media Update
+
+2006/11/13:
+ - Use LogId instead of Time in get_log function
+
+2006/10/31:
+ - remove Purged and Recycle volume size from total pool size
+
+2006/10/26:
+ - Fix javascript sort bug
+ - Add french translation for bweb (template_dir must point to bweb/lang/fr/tpl)
+
+2006/10/14:
+ - Fix Mysql bug for pool display #639
+
+2006/09/20:
+ - Fix SQL query for pool display
+
+2006/09/08:
+ - Eject media takes Location as Autochanger Name
+ - Email is now sent when request to move media
+
+2006/09/06:
+ - Can delete empty location
+ - Drop Bconsole::send_cmd_with_drive and use drive= instead
+ - Use JavaScript to display Human size and time
+
+2006/08/31:
+ - Add FileSet view action
+ - Add view fileset to job_zoom
+
+2006/08/26:
+ - Add more graphics
+   o job avg size/days
+   o job avg size/hours
+   o ...
+
+2006/08/25:
+ - Cleanup
+ - Add more graphics
+    o job/days
+    o job/hours
+    o size/days
+    o size/hours
+    o ... 
+
+2006/08/24:
+ - Add Location log to media zoom view 
+
+2006/08/23:
+ - Add client/media search box (with regexp)
+ - Add menubar instead of plain menu
+ - Drop all <button> element (works now with IE)
+ - Fix big div
+ - Add favicon
+
+2006/08/22:
+ - Add autochanger module (add/del/mod)
+ - Add copyright notice
+
diff --git a/gui/bweb/cgi/bconsole.pl b/gui/bweb/cgi/bconsole.pl
new file mode 100755 (executable)
index 0000000..2bc6748
--- /dev/null
@@ -0,0 +1,121 @@
+#!/usr/bin/perl -w
+use strict;
+
+=head1 NAME
+
+    bconsole.pl - Interface between brestore and bweb to use bconsole.
+
+    You can also use Bconsole.pm and install bconsole on your workstation.
+
+=head1 LICENSE
+
+   Bweb - A Bacula web interface
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+
+   The main author of Bweb is Eric Bollengier.
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation plus additions
+   that are listed in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
+   Switzerland, email:ftf@fsfeurope.org.
+
+=head1 VERSION
+
+    $Id$
+
+=cut
+
+use Data::Dumper;
+use CGI;
+use POSIX qw/strftime/;
+use File::Temp qw/tempfile/;
+
+use Bweb;
+use Bconsole;
+
+my $conf = new Bweb::Config(config_file => $Bweb::config_file);
+$conf->load();
+
+my $bweb = new Bweb(info => $conf);
+my $bconsole = new Bconsole(pref => $conf);
+my $debug = $bweb->{debug};
+
+my $opts = $bweb->get_form('timeout');
+$bconsole->{timeout} = $opts->{timeout} || 40;
+
+# on doit utiliser du POST
+print CGI::header('text/plain');
+
+my @action = CGI::param('action') ;
+my %cmd = ( 'list_job'      => '.job', 
+           'list_client'   => '.client' ,
+           'list_storage'  => '.storage',
+           'list_fileset'  => '.fileset',
+          );
+
+
+my $have_run=0;
+for my $a (@action)
+{
+    if (defined $cmd{$a})
+    {
+       my $out = $bconsole->send_cmd($cmd{$a});
+       $out =~ s/\r\n/;/g ;
+       print "$a=$out\n";
+
+    } elsif ($a eq 'run' and $have_run==0) {
+       $have_run=1;
+
+       my $arg = $bweb->get_form(qw/job client storage fileset 
+                                    where replace priority/);
+
+       my $bootstrap = CGI::param('bootstrap');
+       
+       if (!$bootstrap or !$arg->{job} or !$arg->{client}) {
+           print "ERROR: missing bootstrap or job or client\n";
+           exit 1;
+       }
+
+       my ($fh, $filename) = tempfile();
+       while (my $l = <$bootstrap>) {
+           $fh->print($l);
+       }
+       close($fh);
+       chmod(0644, $filename);
+       
+       my $jobid = $bconsole->run(job       => $arg->{job},
+                                  client    => $arg->{client},
+                                  storage   => $arg->{storage},
+                                  fileset   => $arg->{fileset},
+                                  where     => $arg->{where},
+                                  replace   => $arg->{replace},
+                                  priority  => $arg->{priority},
+                                  bootstrap => $filename);
+
+       print "run=$jobid\n";
+
+    } else {
+       print STDERR "unknow argument $a\n";
+    }
+}
+
+exit 0;
diff --git a/gui/bweb/cgi/bfileview.pl b/gui/bweb/cgi/bfileview.pl
new file mode 100755 (executable)
index 0000000..4feb1d3
--- /dev/null
@@ -0,0 +1,364 @@
+#!/usr/bin/perl -w
+
+=head1 LICENSE
+
+   Bweb - A Bacula web interface
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+
+   The main author of Bweb is Eric Bollengier.
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation plus additions
+   that are listed in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
+   Switzerland, email:ftf@fsfeurope.org.
+
+=head1 VERSION
+
+    $Id$
+
+=cut
+
+use strict;
+use POSIX qw/strftime/;
+use Bweb;
+use CCircle ;
+use Digest::MD5 qw(md5_hex);
+use File::Basename qw/basename dirname/;
+
+my $conf = new Bweb::Config(config_file => $Bweb::config_file);
+$conf->load();
+my $bweb = new Bweb(info => $conf);
+$bweb->connect_db();
+
+my $arg = $bweb->get_form('where', 'jobid');
+my $where = $arg->{where};
+my $jobid = $arg->{jobid};
+my $jobid_url = "jobid=$jobid";
+my $opt_level = 2 ;
+my $max_file = 20;
+my $batch = CGI::param("mode") || '';
+
+my $md5_rep = md5_hex("$where:$jobid") ;
+my $base_url = '/bweb/fv' ;
+my $base_fich = $conf->{fv_write_path};
+
+if ($where and $jobid and $batch eq 'batch') {
+    my $root = fv_get_root_pathid($where);
+    if ($root) {
+       fv_compute_size($jobid, $root);
+       exit 0;
+    }
+    exit 1;
+}
+
+print CGI::header('text/html');
+$bweb->display_begin();
+$bweb->display_job_zoom($jobid);
+
+unless ($where and $jobid) {
+    $bweb->error("Can't get where or jobid");
+    exit 0;
+}
+
+unless ($base_fich and -w $base_fich) {
+    $bweb->error("fv_write_path ($base_fich) is not writable." . 
+                " See Bweb configuration.");
+    exit 0;
+}
+
+if (-f "$base_fich/$md5_rep.png" and -f "$base_fich/$md5_rep.tpl")
+{
+    $bweb->display({}, "$base_fich/$md5_rep.tpl");
+    $bweb->display_end();
+    exit 0;
+}
+my $attribs = fv_get_file_attribute($jobid, $where);
+if ($attribs->{found}) {
+    $bweb->display($attribs, 'fv_file_attribs.tpl');
+    $bweb->display_end();
+    exit 0;
+}
+
+if ($where !~ m!/$!) {
+    $where = $where . "/" ;
+}
+
+my $root = fv_get_root_pathid($where);
+if (!$root) {
+    $bweb->error("Can't find $where in catalog");
+    $bweb->display_end();
+    exit 0;
+}
+
+my $total = fv_compute_size($jobid, $root);
+
+my $url_action = "bfileview.pl?opt_level=$opt_level" ;
+my $top = new CCircle(
+                     display_other => 1,
+                     base_url => "$url_action;$jobid_url;where=$where",
+                     ) ;
+
+fv_display_rep($top, $total, $root, $opt_level) ;
+
+$top->draw_labels() ;
+$top->set_title(Bweb::human_size($total)) ;
+
+open(OUT, ">$base_fich/$md5_rep.png") or die "$base_fich/$md5_rep.png $!";
+# make sure we are writing to a binary stream
+binmode OUT;
+# Convert the image to PNG and print it on standard output
+print OUT $CCircle::gd->png;
+close(OUT) ;
+
+open(OUT, ">$base_fich/$md5_rep.tpl") or die "$base_fich/$md5_rep.tpl $!";
+print OUT "
+ <form action='$url_action' method='get'>
+  <div align='right'>
+   <input title='jobids' type='hidden' name='jobid' value='$jobid'>
+   <input title='repertoire' type='text' name='where' value='$where'/>
+   <input type='submit' size='256' name='go' value='go'/>
+  </div>
+ </form>
+ <br/>
+" ;
+
+print OUT $top->get_imagemap($where, "$base_url/$md5_rep.png") ;
+close(OUT) ;
+
+$bweb->display({}, "$base_fich/$md5_rep.tpl");
+$bweb->display_end();
+
+sub fv_display_rep
+{
+    my ($ccircle, $max, $rep, $level) = @_ ;
+    return if ($max < 1);
+
+    my $sum = 0;
+    my $dirs = fv_list_dirs($jobid, $rep);     # 0: pathid, 1: pathname
+
+    foreach my $dir (@{$dirs})
+    {
+       my $size = fv_compute_size($jobid, $dir->[0]);
+       $sum += $size;
+
+       my $per = $size * 100 / $max;
+       my $chld = $ccircle->add_part($per, 
+                                     basename($dir->[1]) . '/',
+                                     basename($dir->[1]) 
+                                      . sprintf(' %.0f%% ', $per)
+                                      . Bweb::human_size($size)
+                                     ) ;
+       
+       if ($chld and $level > 0) {
+           fv_display_rep($chld, $size, $dir->[0], $level - 1) ;
+       }
+    }
+
+    # 0: name, 1: size
+    my $files = fv_get_big_files($jobid, $rep, 3*100/$max, $max_file/($level+1));
+    foreach my $f (@{$files}) {
+       $ccircle->add_part($f->[1] * 100 / $max, 
+                          $f->[0],
+                          $f->[0] . "\n" . Bweb::human_size($f->[1]));
+       $sum += $f->[1];
+    }
+
+    if ($sum < $max) {
+       $ccircle->add_part(($max - $sum) * 100 / $max, 
+                          "other files < 3%",
+                          "other\n" . Bweb::human_size($max - $sum));
+    }
+
+    $ccircle->finalize() ;
+}
+
+sub fv_compute_size
+{
+    my ($jobid, $rep) = @_;
+
+    my $size = fv_get_size($jobid, $rep);
+    if ($size) {
+       return $size;
+    }
+
+    $size = fv_get_files_size($jobid, $rep);
+
+    my $dirs = fv_list_dirs($jobid, $rep);
+    foreach my $dir (@{$dirs}) {
+       $size += fv_compute_size($jobid, $dir->[0]);
+    }
+    
+    fv_update_size($jobid, $rep, $size);
+    return $size;
+}
+
+sub fv_list_dirs
+{
+    my ($jobid, $rep) = @_;
+
+    my $ret = $bweb->dbh_selectall_arrayref("
+      SELECT P.PathId,
+             (
+              SELECT Path FROM Path WHERE PathId = P.PathId
+              UNION 
+              SELECT Path FROM brestore_missing_path WHERE PathId = P.PathId
+             ) AS Path
+        FROM (
+          SELECT PathId
+            FROM brestore_pathvisibility 
+      INNER JOIN brestore_pathhierarchy USING (PathId)
+           WHERE PPathId  = $rep
+             AND JobId = $jobid
+             ) AS P
+");
+
+    return $ret;
+}
+
+sub fv_get_file_attribute
+{
+    my ($jobid, $full_name) = @_;
+    
+    my $filename = $bweb->dbh_quote(basename($full_name));
+    my $path     = $bweb->dbh_quote(dirname($full_name) . "/");
+
+    my $attr = $bweb->dbh_selectrow_hashref("
+ SELECT 1    AS found,
+        MD5  AS md5,
+        base64_decode_lstat(8,  LStat) AS size,
+        base64_decode_lstat(11, LStat) AS atime,
+        base64_decode_lstat(12, LStat) AS mtime,
+        base64_decode_lstat(13, LStat) AS ctime
+
+   FROM File INNER JOIN Filename USING (FilenameId)
+             INNER JOIN Path     USING (PathId)
+  WHERE Name  = $filename
+   AND  Path  = $path
+   AND  JobId = $jobid
+");
+
+    $attr->{filename} = $full_name;
+    $attr->{size} = Bweb::human_size($attr->{size});
+    foreach my $d (qw/atime ctime mtime/) {
+       $attr->{$d} = strftime('%F %H:%M', localtime($attr->{$d}));
+    }
+    return $attr;
+}
+
+sub fv_get_size
+{
+    my ($jobid, $rep) = @_;
+
+    my $ret = $bweb->dbh_selectrow_hashref("
+ SELECT Size AS size
+   FROM brestore_pathvisibility
+  WHERE PathId = $rep
+    AND JobId = $jobid
+");
+
+    return $ret->{size};
+}
+
+sub fv_get_files_size
+{
+    my ($jobid, $rep) = @_;
+
+    my $ret = $bweb->dbh_selectrow_hashref("
+ SELECT sum(base64_decode_lstat(8,LStat)) AS size
+   FROM File
+  WHERE PathId  = $rep
+    AND JobId = $jobid
+");
+
+    return $ret->{size};
+}
+
+sub fv_get_big_files
+{
+    my ($jobid, $rep, $min, $limit) = @_;
+
+    my $ret = $bweb->dbh_selectall_arrayref("
+   SELECT Name, size
+   FROM (
+         SELECT FilenameId,base64_decode_lstat(8,LStat) AS size
+           FROM File
+          WHERE PathId  = $rep
+            AND JobId = $jobid
+        ) AS S INNER JOIN Filename USING (FilenameId)
+   WHERE S.size > $min
+   ORDER BY S.size DESC
+   LIMIT $limit
+");
+
+    return $ret;
+}
+
+sub fv_update_size
+{
+    my ($jobid, $rep, $size) = @_;
+
+    my $nb = $bweb->dbh_do("
+ UPDATE brestore_pathvisibility SET Size = $size 
+  WHERE JobId = $jobid 
+    AND PathId = $rep 
+");
+
+    return $nb;
+}
+
+sub fv_get_root_pathid
+{
+    my ($path) = @_;
+    $path = $bweb->dbh_quote($path);
+    my $ret = $bweb->dbh_selectrow_hashref("
+SELECT PathId FROM Path WHERE Path = $path
+   UNION 
+SELECT PathId FROM brestore_missing_path WHERE PATH = $path
+");
+    return $ret->{pathid};
+}
+
+__END__
+
+CREATE OR REPLACE FUNCTION base64_decode_lstat(int4, varchar) RETURNS int8 AS $$
+DECLARE
+val int8;
+b64 varchar(64);
+size varchar(64);
+i int;
+BEGIN
+size := split_part($2, ' ', $1);
+b64 := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+val := 0;
+FOR i IN 1..length(size) LOOP
+val := val + (strpos(b64, substr(size, i, 1))-1) * (64^(length(size)-i));
+END LOOP;
+RETURN val;
+END;
+$$ language 'plpgsql';
+
+ALTER TABLE brestore_pathvisibility ADD Size  int8;
+
+
+
+ALTER TABLE brestore_pathvisibility ADD Files int4;
diff --git a/gui/bweb/cgi/bgraph.pl b/gui/bweb/cgi/bgraph.pl
new file mode 100755 (executable)
index 0000000..c7540c7
--- /dev/null
@@ -0,0 +1,490 @@
+#!/usr/bin/perl -w
+use strict;
+
+=head1 LICENSE
+
+   Bweb - A Bacula web interface
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+
+   The main author of Bweb is Eric Bollengier.
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation plus additions
+   that are listed in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
+   Switzerland, email:ftf@fsfeurope.org.
+
+=head1 VERSION
+
+    $Id$
+
+=cut
+
+use Bweb;
+
+use Data::Dumper;
+use CGI;
+
+use POSIX qw/strftime/;
+use File::Basename qw/basename dirname/;
+
+my $conf = new Bweb::Config(config_file => $Bweb::config_file);
+$conf->load();
+
+my $bweb = new Bweb(info => $conf);
+$bweb->connect_db();
+my $dbh = $bweb->{dbh};
+my $debug = $bweb->{debug};
+
+my $graph = CGI::param('graph') || 'job_size';
+my $legend = CGI::param('legend') || 'on' ;
+$legend = ($legend eq 'on')?1:0;
+
+my $arg = $bweb->get_form(qw/width height limit offset age where jobid
+                            jfilesets level status jjobnames jclients/);
+
+my ($limitq, $label) = $bweb->get_limit(age   => $arg->{age},
+                                       limit => $arg->{limit},
+                                       offset=> $arg->{offset},
+                                       order => 'Job.StartTime ASC',
+                                       );
+
+my $statusq='';
+if ($arg->{status} and $arg->{status} ne 'Any') {
+    $statusq = " AND Job.JobStatus = '$arg->{status}' ";
+}
+    
+my $levelq='';
+if ($arg->{level} and $arg->{level} ne 'Any') {
+    $levelq = " AND Job.Level = '$arg->{level}' ";
+} 
+
+my $filesetq='';
+if ($arg->{jfilesets}) {
+    $filesetq = " AND FileSet.FileSet IN ($arg->{qfilesets}) ";
+} 
+
+my $jobnameq='';
+if ($arg->{jjobnames}) {
+    $jobnameq = " AND Job.Name IN ($arg->{jjobnames}) ";
+} else {
+    $arg->{jjobnames} = 'all'; # skip warning
+} 
+
+my $clientq='';
+if ($arg->{jclients}) {
+    $clientq = " AND Client.Name IN ($arg->{jclients}) ";
+} else {
+    $arg->{jclients} = 'all';  # skip warning
+}
+
+my $gtype = CGI::param('gtype') || 'bars';
+
+print CGI::header('image/png');
+
+sub get_graph
+{
+    my (@options) = @_;
+    my $graph;
+    if ($gtype eq 'lines') {
+       use GD::Graph::lines;
+       $graph = GD::Graph::lines->new ( $arg->{width}, $arg->{height} );
+
+    } elsif ($gtype eq 'bars') {
+       use GD::Graph::bars;
+       $graph = GD::Graph::bars->new ( $arg->{width}, $arg->{height} );
+
+    } elsif ($gtype eq 'linespoints') {
+       use GD::Graph::linespoints;
+       $graph = GD::Graph::linespoints->new ( $arg->{width}, $arg->{height} );
+
+#   this doesnt works at this time
+#    } elsif ($gtype eq 'bars3d') {
+#      use GD::Graph::bars3d;
+#      $graph = GD::Graph::bars3d->new ( $arg->{width}, $arg->{height} );
+
+    } else {
+       return undef;
+    }
+
+    $graph->set('x_label' => 'Time',
+               'x_number_format' => sub { strftime('%D', localtime($_[0])) },
+               'x_tick_number' => 1,
+               @options,
+               );
+
+    return $graph;
+}
+
+sub make_tab
+{
+    my ($all_row) = @_;
+
+    my $i=0;
+    my $last_date=0;
+
+    my $ret = {};
+    
+    foreach my $row (@$all_row) {
+       my $label = $row->[1] . "/" . $row->[2] ; # client/backup name
+
+       $ret->{date}->[$i]   = $row->[0];       
+       $ret->{$label}->[$i] = $row->[3];
+       $i++;
+       $last_date = $row->[0];
+    }
+
+    # insert a fake element
+    foreach my $elt ( keys %{$ret}) {
+       $ret->{$elt}->[$i] =  undef;
+    }
+
+    $ret->{date}->[$i] = $last_date + 1;
+
+    my $date = $ret->{date} ;
+    delete $ret->{date};
+
+    return ($date, $ret);
+}
+
+sub make_tab_sum
+{
+    my ($all_row) = @_;
+
+    my $i=0;
+    my $last_date=0;
+
+    my $ret = {};
+    
+    foreach my $row (@$all_row) {
+       $ret->{date}->[$i]   = $row->[0];       
+       $ret->{nb}->[$i] = $row->[1];
+       $i++;
+    }
+
+    return ($ret);
+}
+
+if ($graph eq 'job_size') {
+
+    my $query = "
+SELECT 
+       UNIX_TIMESTAMP(Job.StartTime)    AS starttime,
+       Client.Name                      AS clientname,
+       Job.Name                         AS jobname,
+       Job.JobBytes                     AS jobbytes
+FROM Job, Client, FileSet
+WHERE Job.ClientId = Client.ClientId
+  AND Job.FileSetId = FileSet.FileSetId
+  AND Job.Type = 'B'
+  $clientq
+  $statusq
+  $filesetq
+  $levelq
+  $jobnameq
+$limitq
+";
+
+    print STDERR $query if ($debug);
+
+    my $obj = get_graph('title' => "Job Size : $arg->{jclients}/$arg->{jjobnames}",
+                       'y_label' => 'Size',
+                       'y_min_value' => 0,
+                       'y_number_format' => \&Bweb::human_size,
+                       );
+
+    my $all = $dbh->selectall_arrayref($query) ;
+
+    my ($d, $ret) = make_tab($all);
+    if ($legend) {
+       $obj->set_legend(keys %$ret);
+    }
+    print $obj->plot([$d, values %$ret])->png;
+}
+
+if ($graph eq 'job_file') {
+
+    my $query = "
+SELECT 
+       UNIX_TIMESTAMP(Job.StartTime)    AS starttime,
+       Client.Name                      AS clientname,
+       Job.Name                         AS jobname,
+       Job.JobFiles                     AS jobfiles
+FROM Job, Client, FileSet
+WHERE Job.ClientId = Client.ClientId
+  AND Job.FileSetId = FileSet.FileSetId
+  AND Job.Type = 'B'
+  $clientq
+  $statusq
+  $filesetq
+  $levelq
+  $jobnameq
+$limitq
+";
+
+    print STDERR $query if ($debug);
+
+    my $obj = get_graph('title' => "Job Files : $arg->{jclients}/$arg->{jjobnames}",
+                       'y_label' => 'Number Files',
+                       'y_min_value' => 0,
+                       );
+
+    my $all = $dbh->selectall_arrayref($query) ;
+
+    my ($d, $ret) = make_tab($all);
+    if ($legend) {
+       $obj->set_legend(keys %$ret);
+    }
+    print $obj->plot([$d, values %$ret])->png;
+}
+
+# it works only with postgresql at this time
+elsif ($graph eq 'file_histo' and $arg->{where}) {
+    
+    my $dir  = $dbh->quote(dirname($arg->{where}) . '/');
+    my $file = $dbh->quote(basename($arg->{where}));
+
+    my $query = "
+SELECT UNIX_TIMESTAMP(Job.StartTime)    AS starttime,
+       Client.Name                      AS client,
+       Job.Name                         AS jobname,
+       base64_decode_lstat(8,LStat)     AS lstat
+
+FROM Job, Client, FileSet, Filename, Path, File
+WHERE Job.ClientId = Client.ClientId
+  AND Job.FileSetId = FileSet.FileSetId
+  AND Job.Type = 'B'
+  AND File.JobId = Job.JobId
+  AND File.FilenameId = Filename.FilenameId
+  AND File.PathId = Path.PathId
+  AND Path.Path = $dir
+  AND Filename.Name = $file
+  $clientq
+  $statusq
+  $filesetq
+  $levelq
+  $jobnameq
+$limitq
+";
+
+    print STDERR $query if ($debug);
+
+    my $all = $dbh->selectall_arrayref($query) ;
+
+    my $obj = get_graph('title' => "File size : $arg->{where}",
+                       'y_label' => 'File size',
+                       'y_min_value' => 0,
+                       'y_min_value' => 0,
+                       'y_number_format' => \&Bweb::human_size,
+                       );
+
+
+    my ($d, $ret) = make_tab($all);
+    if ($legend) {
+       $obj->set_legend(keys %$ret);
+    }
+    print $obj->plot([$d, values %$ret])->png;
+}
+
+# it works only with postgresql at this time
+# TODO: use brestore_missing_path
+elsif ($graph eq 'rep_histo' and $arg->{where}) {
+    
+    my $dir  = $arg->{where};
+    $dir .= '/' if ($dir !~ m!/$!);
+    $dir = $dbh->quote($dir);
+
+    my $query = "
+SELECT UNIX_TIMESTAMP(Job.StartTime) AS starttime,
+       Client.Name                   AS client,
+       Job.Name                      AS jobname,
+       brestore_pathvisibility.size  AS size
+
+FROM Job, Client, FileSet, Path, brestore_pathvisibility
+WHERE Job.ClientId = Client.ClientId
+  AND Job.FileSetId = FileSet.FileSetId
+  AND Job.Type = 'B'
+  AND Job.JobId = brestore_pathvisibility.JobId
+  AND Path.PathId = brestore_pathvisibility.PathId
+  AND Path.Path = $dir
+  $clientq
+  $statusq
+  $filesetq
+  $levelq
+  $jobnameq
+$limitq
+";
+
+    print STDERR $query if ($debug);
+
+    my $all = $dbh->selectall_arrayref($query) ;
+
+    my $obj = get_graph('title' => "Directory size : $arg->{where}",
+                       'y_label' => 'Directory size',
+                       'y_min_value' => 0,
+                       'y_min_value' => 0,
+                       'y_number_format' => \&Bweb::human_size,
+                       );
+
+
+    my ($d, $ret) = make_tab($all);
+    if ($legend) {
+       $obj->set_legend(keys %$ret);
+    }
+    print $obj->plot([$d, values %$ret])->png;
+}
+
+elsif ($graph eq 'job_rate') {
+
+    my $query = "
+SELECT 
+       UNIX_TIMESTAMP(Job.StartTime)                          AS starttime,
+       Client.Name                      AS clientname,
+       Job.Name                         AS jobname,
+       Job.JobBytes /
+       ($bweb->{sql}->{SEC_TO_INT}(
+                          $bweb->{sql}->{UNIX_TIMESTAMP}(EndTime)  
+                        - $bweb->{sql}->{UNIX_TIMESTAMP}(StartTime)) + 0.01) 
+         AS rate
+
+FROM Job, Client, FileSet
+WHERE Job.ClientId = Client.ClientId
+  AND Job.FileSetId = FileSet.FileSetId
+  AND Job.Type = 'B'
+  $clientq
+  $statusq
+  $filesetq
+  $levelq
+  $jobnameq
+$limitq
+";
+
+    print STDERR $query if ($debug);
+
+    my $obj = get_graph('title' => "Job Rate : $arg->{jclients}/$arg->{jjobnames}",
+                       'y_label' => 'Rate b/s',
+                       'y_min_value' => 0,
+                       'y_number_format' => \&Bweb::human_size,
+                       );
+
+    my $all = $dbh->selectall_arrayref($query) ;
+
+    my ($d, $ret) = make_tab($all);    
+    if ($legend) {
+       $obj->set_legend(keys %$ret);
+    }
+    print $obj->plot([$d, values %$ret])->png;
+}
+
+
+
+elsif ($graph eq 'job_duration') {
+
+    my $query = "
+SELECT 
+       UNIX_TIMESTAMP(Job.StartTime)                           AS starttime,
+       Client.Name                                             AS clientname,
+       Job.Name                                                AS jobname,
+  $bweb->{sql}->{SEC_TO_INT}(  $bweb->{sql}->{UNIX_TIMESTAMP}(EndTime)  
+                             - $bweb->{sql}->{UNIX_TIMESTAMP}(StartTime)) 
+         AS duration
+FROM Job, Client, FileSet
+WHERE Job.ClientId = Client.ClientId
+  AND Job.FileSetId = FileSet.FileSetId
+  AND Job.Type = 'B'
+  $clientq
+  $statusq
+  $filesetq
+  $levelq
+  $jobnameq
+$limitq
+";
+
+    print STDERR $query if ($debug);
+
+    my $obj = get_graph('title' => "Job Duration : $arg->{jclients}/$arg->{jjobnames}",
+                       'y_label' => 'Duration',
+                       'y_min_value' => 0,
+                       'y_number_format' => \&Bweb::human_sec,
+                       );
+    my $all = $dbh->selectall_arrayref($query) ;
+
+    my ($d, $ret) = make_tab($all);
+    if ($legend) {
+       $obj->set_legend(keys %$ret);
+    }
+    print $obj->plot([$d, values %$ret])->png;
+
+
+# number of job per day/hour
+} elsif ($graph =~ /^job_(count|sum|avg)_((p?)(day|hour|month))$/) {
+    my $t = $1;
+    my $d = uc($2);
+    my $per_t = $3;
+    my ($limit, $label) = $bweb->get_limit(age   => $arg->{age},
+                                          limit => $arg->{limit},
+                                          offset=> $arg->{offset},
+                                          groupby => "A",
+                                          );
+    my @arg;                   # arg for plotting
+
+    if (!$per_t) {             # much better aspect
+       #$gtype = 'lines';
+    } else {
+       push @arg, ("x_number_format" => undef,
+                   "x_min_value" => 0,
+                   );
+    }
+
+    if ($t eq 'sum' or $t eq 'avg') {
+       push @arg, ('y_number_format' => \&Bweb::human_size);
+    }
+
+    my $query = "
+SELECT
+     " . ($per_t?"":"UNIX_TIMESTAMP") . "(" . $bweb->{sql}->{"STARTTIME_$d"} . ") AS A,
+     $t(JobBytes)                  AS nb
+FROM Job, Client, FileSet
+WHERE Job.ClientId = Client.ClientId
+  AND Job.FileSetId = FileSet.FileSetId
+  AND Job.Type = 'B'
+  $clientq
+  $statusq
+  $filesetq
+  $levelq
+  $jobnameq
+$limit
+";
+
+    print STDERR $query  if ($debug);
+
+    my $obj = get_graph('title' => "Job $t : $arg->{jclients}/$arg->{jjobnames}",
+                       'y_label' => $t,
+                       'y_min_value' => 0,
+                       @arg,
+                       );
+
+    my $all = $dbh->selectall_arrayref($query) ;
+    my ($ret) = make_tab_sum($all);
+
+    print $obj->plot([$ret->{date}, $ret->{nb}])->png;    
+}
+
diff --git a/gui/bweb/cgi/bweb.pl b/gui/bweb/cgi/bweb.pl
new file mode 100755 (executable)
index 0000000..6b3dd7d
--- /dev/null
@@ -0,0 +1,413 @@
+#!/usr/bin/perl -w
+use strict ;
+
+=head1 LICENSE
+
+   Bweb - A Bacula web interface
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+
+   The main author of Bweb is Eric Bollengier.
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation plus additions
+   that are listed in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
+   Switzerland, email:ftf@fsfeurope.org.
+
+=head1 VERSION
+
+    $Id$
+
+=cut
+
+use Data::Dumper;
+use Bweb;
+use CGI;
+
+my $client_re = qr/^([\w\d\.-]+)$/;
+
+my $action = CGI::param('action') || 'begin';
+
+if ($action eq 'restore') {
+    print CGI::header('text/brestore');        # specialy to run brestore.pl
+
+} else {
+    print CGI::header('text/html');
+}
+
+# loading config file
+my $conf = new Bweb::Config(config_file => $Bweb::config_file);
+$conf->load();
+
+my $bweb = new Bweb(info => $conf);
+
+# just send data with text/brestore content
+if ($action eq 'restore') {
+    $bweb->restore();
+    exit 0;
+}
+
+my $arg = $bweb->get_form('jobid', 'limit', 'offset', 'age');
+
+$bweb->display_begin();
+
+# if no configuration, we send edit_conf
+if ($action ne 'apply_conf' and !$bweb->{info}->{dbi}) {
+    $action = 'edit_conf';
+}
+
+if ($action eq 'begin') {              # main display
+    print "<div style='left=0;'><table border='0'><tr><td valign='top' width='100%'>\n";
+    $bweb->display_general(age => $arg->{age});
+    $bweb->display_running_jobs(0);
+    print "</td><td valign='top'>";
+    $bweb->display({}, "stats.tpl");
+    print "</td></tr></table></div>";
+    $bweb->display_job(limit => 10); 
+
+} elsif ($action eq 'view_conf') {
+    $conf->view()
+
+} elsif ($action eq 'edit_conf') {
+    $conf->edit();
+
+} elsif ($action eq 'apply_conf') {
+    $conf->modify();
+
+} elsif ($action eq 'client') {        
+    $bweb->display_clients();
+
+} elsif ($action eq 'pool') {
+    $bweb->display_pool();
+
+} elsif ($action eq 'location_edit') {
+    $bweb->location_edit();
+
+} elsif ($action eq 'location_save') {
+    $bweb->location_save();
+
+} elsif ($action eq 'location_add') {
+    $bweb->location_add();
+
+} elsif ($action eq 'location_del') {
+    $bweb->location_del();
+
+} elsif ($action eq 'media') {
+    print "<div><table border='0'><tr><td valign='top'>\n";
+    my $fields = $bweb->get_form(qw/db_locations db_pools
+                                   qlocations qpools volstatus qre_media
+                                   limit  qmediatypes db_mediatypes/);
+    $bweb->display($fields, "display_form_media.tpl");
+
+    print "</td><td valign='top'>";
+    $bweb->display_media();
+    print "</td></tr></table></div>";
+
+} elsif ($action eq 'medias') {
+    $bweb->display_medias();
+
+} elsif ($action eq 'eject') {
+    my $arg = $bweb->get_form("ach");
+    my $a = $bweb->ach_get($arg->{ach});
+    
+    if ($a) {
+       $a->status();
+       foreach my $slot (CGI::param('slot')) {
+           print $a->{error} unless $a->send_to_io($slot);
+       }
+
+       foreach my $media (CGI::param('media')) {
+           my $slot = $a->get_media_slot($media);
+           print $a->{error} unless $a->send_to_io($slot);
+       }
+
+       $a->display_content();
+    }
+
+} elsif ($action eq 'eject_media') {
+    $bweb->eject_media();
+
+} elsif ($action eq 'clear_io') {
+    my $arg = $bweb->get_form('ach');
+
+    my $a = $bweb->ach_get($arg->{ach});
+    if (defined $a) {
+       $a->status();
+       $a->clear_io();
+       $a->display_content();
+    }
+
+} elsif ($action eq 'ach_edit') {
+    $bweb->ach_edit();
+
+} elsif ($action eq 'ach_del') {
+    $bweb->ach_del();
+
+} elsif ($action eq 'ach_view') {
+    # TODO : get autochanger name and create it
+    $bweb->connect_db();
+    my $arg = $bweb->get_form('ach');
+
+    my $a = $bweb->ach_get($arg->{ach});
+    if ($a) {
+       $a->status();
+       $a->display_content();
+    }
+
+} elsif ($action eq 'ach_add') {
+    $bweb->ach_add();
+
+} elsif ($action eq 'ach_load') {
+    my $arg = $bweb->get_form('ach', 'drive', 'slot');
+    
+    my $a = $bweb->ach_get($arg->{ach});
+
+    if (defined $a and defined $arg->{drive} and defined $arg->{slot})
+    {
+       my $b = new Bconsole(pref => $conf, timeout => 300, log_stdout => 1) ;
+       # TODO : use template here
+       print "<pre>\n";
+       $b->send_cmd("mount slot=$arg->{slot} drive=$arg->{drive} storage=\"" . $a->get_drive_name($arg->{drive}) . '"');
+       print "</pre>\n";
+    } else {
+       $bweb->error("Can't get drive, slot or ach");
+    }
+    
+} elsif ($action eq 'ach_unload') {
+    my $arg = $bweb->get_form('drive', 'slot', 'ach');
+
+    my $a = $bweb->ach_get($arg->{ach});
+
+    if (defined $a and defined $arg->{drive} and defined $arg->{slot})
+    {
+       my $b = new Bconsole(pref => $conf, timeout => 300, log_stdout => 1) ;
+       # TODO : use template here
+       print "<pre>\n";
+       $b->send_cmd("umount drive=$arg->{drive} storage=\"" . $a->get_drive_name($arg->{drive}) . '"');
+       print "</pre>\n";
+
+    } else {
+       $bweb->error("Can't get drive, slot or ach");
+    }   
+} elsif ($action eq 'intern_media') {
+    $bweb->help_intern();
+
+} elsif ($action eq 'compute_intern_media') {
+    $bweb->help_intern_compute();
+
+} elsif ($action eq 'extern_media') {
+    $bweb->help_extern();
+
+} elsif ($action eq 'compute_extern_media') {
+    $bweb->help_extern_compute();
+
+} elsif ($action eq 'extern') {
+    print "<div style='float: left;'>";
+    my @achs = $bweb->eject_media();
+    for my $ach (@achs) {
+        CGI::param('ach', $ach);
+       $bweb->update_slots();
+    }
+    print "</div><div style='float: left;margin-left: 20px;'>";
+    $bweb->move_media();
+    print "</div>";
+
+} elsif ($action eq 'move_email') {
+    $bweb->move_email();
+
+} elsif ($action eq 'change_location') {
+    $bweb->change_location();
+
+} elsif ($action eq 'location') {
+    $bweb->display_location();
+
+} elsif ($action eq 'about') {
+    $bweb->display($bweb, 'about.tpl');
+
+} elsif ($action eq 'intern') {
+    $bweb->move_media(); # TODO : remove that
+
+} elsif ($action eq 'move_media') {
+    $bweb->move_media(); 
+
+} elsif ($action eq 'save_location') {
+    $bweb->save_location();
+
+} elsif ($action eq 'update_location') {
+    $bweb->update_location();
+
+} elsif ($action eq 'update_media') {
+    $bweb->update_media();
+
+} elsif ($action eq 'do_update_media') {
+    $bweb->do_update_media();
+
+} elsif ($action eq 'update_slots') {
+    $bweb->update_slots();
+
+} elsif ($action eq 'graph') {
+    $bweb->display_graph();
+
+} elsif ($action eq 'next_job') {
+    $bweb->director_show_sched();
+
+} elsif ($action eq 'enable_job') {
+    $bweb->enable_disable_job(1);
+
+} elsif ($action eq 'disable_job') {
+    $bweb->enable_disable_job(0);
+
+} elsif ($action eq 'job') {
+
+    print "<div><table border='0'><tr><td valign='top'>\n";
+    my $fields = $bweb->get_form(qw/status level db_clients db_filesets
+                                   limit age offset qclients qfilesets
+                                   jobtype qpools db_pools/);
+    $bweb->display($fields, "display_form_job.tpl");
+
+    print "</td><td valign='top'>";
+    $bweb->display_job(age => $arg->{age},  # last 7 days
+                      offset => $arg->{offset},
+                      limit => $arg->{limit});
+    print "</td></tr></table></div>";
+} elsif ($action eq 'client_stats') {
+
+    foreach my $client (CGI::param('client')) {
+       if ($client =~ m/$client_re/) {
+           $bweb->display_client_stats(clientname => $1,
+                                       age => $arg->{age});
+       }
+    }
+
+} elsif ($action eq 'running') {
+    $bweb->display_running_jobs(1);
+
+} elsif ($action eq 'dsp_cur_job') {
+    $bweb->display_running_job();
+
+} elsif ($action eq 'update_from_pool') {
+    my $elt = $bweb->get_form(qw/media pool/);
+    unless ($elt->{media} || $elt->{pool}) {
+       $bweb->error("Can't get media or pool param");
+    } else {
+       my $b = new Bconsole(pref => $conf) ;
+
+       $bweb->display({
+ content => $b->send_cmd("update volume=$elt->{media} fromPool=$elt->{pool}"),
+ title => "Update pool",
+ name => "update volume=$elt->{media} fromPool=$elt->{pool}",
+       }, "command.tpl");      
+    }
+    
+    $bweb->update_media();
+
+} elsif ($action eq 'client_status') {
+    my $b;
+    foreach my $client (CGI::param('client')) {
+       if ($client =~ m/$client_re/) {
+           $client = $1;
+           $b = new Bconsole(pref => $conf) 
+               unless ($b) ;
+
+           $bweb->display({
+               content => $b->send_cmd("st client=$client"),
+               title => "Client status",
+               name => $client,
+           }, "command.tpl");
+           
+       } else {
+           $bweb->error("Can't get client selection");
+       }
+    }
+
+} elsif ($action eq 'cancel_job') {
+    $bweb->cancel_job();
+
+} elsif  ($action eq 'media_zoom') {
+    $bweb->display_media_zoom();
+
+} elsif  ($action eq 'job_zoom') {
+    if ($arg->{jobid}) {
+       $bweb->display_job_zoom($arg->{jobid});
+       $bweb->get_job_log();
+    } 
+} elsif ($action eq 'job_log') {
+    $bweb->get_job_log();
+
+} elsif ($action eq 'prune') {
+    $bweb->prune();
+
+} elsif ($action eq 'purge') {
+    $bweb->purge();
+
+} elsif ($action eq 'run_job') {
+    $bweb->run_job();
+
+} elsif ($action eq 'run_job_mod') {
+    $bweb->run_job_mod();
+
+} elsif ($action eq 'run_job_now') {
+    $bweb->run_job_now();
+
+} elsif ($action eq 'label_barcodes') {
+    $bweb->label_barcodes();
+
+} elsif ($action eq 'delete') {
+    $bweb->delete();
+
+} elsif ($action eq 'fileset_view') {
+    $bweb->fileset_view();
+
+} else {
+    $bweb->error("Sorry, this action don't exist");
+}
+
+$bweb->display_end();
+
+
+__END__
+
+TODO :
+
+ o Affichage des job en cours, termines
+ o Affichage du detail d'un job (status client)
+ o Acces aux log d'une sauvegarde
+ o Cancel d'un job
+ o Lancement d'un job
+
+ o Affichage des medias (pool, cf bacweb)
+ o Affichage de la liste des cartouches
+ o Affichage d'un autochangeur
+ o Mise a jour des slots
+ o Label barcodes
+ o Affichage des medias qui ont besoin d'etre change
+
+ o Affichage des stats sur les dernieres sauvegardes (cf bacula-web)
+ o Affichage des stats sur un type de job
+ o Affichage des infos de query.sql
+
+ - Affichage des du TapeAlert sur le site
+ - Recuperation des erreurs SCSI de /var/log/kern.log
+
+ o update d'un volume
+ o update d'un pool
+
+ o Configuration des autochanger a la main dans un hash dumper
diff --git a/gui/bweb/html/A.png b/gui/bweb/html/A.png
new file mode 100644 (file)
index 0000000..89c2124
Binary files /dev/null and b/gui/bweb/html/A.png differ
diff --git a/gui/bweb/html/E.png b/gui/bweb/html/E.png
new file mode 100644 (file)
index 0000000..89c2124
Binary files /dev/null and b/gui/bweb/html/E.png differ
diff --git a/gui/bweb/html/R.png b/gui/bweb/html/R.png
new file mode 100644 (file)
index 0000000..166c220
Binary files /dev/null and b/gui/bweb/html/R.png differ
diff --git a/gui/bweb/html/T.png b/gui/bweb/html/T.png
new file mode 100644 (file)
index 0000000..d92d88d
Binary files /dev/null and b/gui/bweb/html/T.png differ
diff --git a/gui/bweb/html/W.png b/gui/bweb/html/W.png
new file mode 100644 (file)
index 0000000..6d7dbad
Binary files /dev/null and b/gui/bweb/html/W.png differ
diff --git a/gui/bweb/html/add.png b/gui/bweb/html/add.png
new file mode 100644 (file)
index 0000000..062d005
Binary files /dev/null and b/gui/bweb/html/add.png differ
diff --git a/gui/bweb/html/apply.png b/gui/bweb/html/apply.png
new file mode 100644 (file)
index 0000000..58a64cf
Binary files /dev/null and b/gui/bweb/html/apply.png differ
diff --git a/gui/bweb/html/bweb.css b/gui/bweb/html/bweb.css
new file mode 100644 (file)
index 0000000..0b8e66e
--- /dev/null
@@ -0,0 +1,123 @@
+body { background-color: #ffffff; font-family: verdana,arial,helvetica; font-size: 8pt;}
+a { text-decoration: none;}
+.code_display   {       background-color: #b9b9ac;
+                        border: 1px solid #9d9d94;
+}
+
+abutton.formulaire { font-size: 9pt; height: 48px; width: 80px; background-color: transparent; }
+
+button.formulaire { border: 0px; font-size: 9pt;  background-color: transparent; }
+
+td.joberr { background-color: red; color: white;}
+
+.pSlice, .pSliceFull, .pSliceError, .pSliceAppend, .pSlicePurged, .pSliceRecycle, 
+.pSliceArchive, .pSliceUsed, .pSliceRead_Only, .pSliceDisabled,
+.pSliceOk,.pSliceWarn,.pSliceCrit,.pSliceEmpty
+ {
+  width: 2px;
+  height: 9px;
+  margin-right: 1px;
+  margin-bottom: 1px;
+  border: solid 1px #CCCCCC;
+  background-color: #E6E6E6;   
+}
+
+.pSliceFull, .pSliceRead_Only,.pSliceArchive, .pSliceUsed, .pSliceDisabled,
+.pSliceCrit {
+ border: solid 1px #BD0C10;
+ background-color: #FF3029;
+}
+
+.pSliceError {
+ border: solid 1px #000000;
+ background-color: #020202;
+}
+
+.pSliceAppend, .pSliceWarn {
+ border: solid 1px #CD6500;
+ background-color: #FFCE00;
+}
+
+.pSlicePurged, .pSliceRecycle, .pSliceOk {
+ border: solid 1px #009900;
+ background-color: #00FF00;
+}
+
+input.button {
+  border: 0px;
+  margin: 0 5px 0 5px;
+  padding: 0 0 0 0;
+}
+
+#menu, #menu ul {
+       float: left;
+       list-style: none;
+       line-height: 1;
+       background:#eeeae6 ;
+       font-weight: bold;
+       padding: 0;
+       border: solid #999;
+       border-width: 1px 0;
+       margin: 0 0 1em 0;
+       padding: 0.25em 2em;
+        width: 100%;
+       color: #7C6240;
+}
+
+#menu a {
+       display: block;
+       color: #7C6240;
+       text-decoration: none;
+       padding: 0.25em 2em;
+}
+
+#menu a.daddy {
+       background: url(right.gif) center right no-repeat;
+}
+
+#menu li {
+       float: left;
+       padding: 0;
+}
+
+#menu li ul {
+       position: absolute;
+       left: -999em;
+       height: auto;
+       width: 14.4em;
+       border-width: 1px;
+}
+
+#logged {
+       padding: 0.25em 2em;
+       float: right;
+       clear: left;
+       text-align: right;
+
+}
+
+#menu li li {
+       padding-right: 1em;
+}
+
+#menu li ul a {
+}
+
+#menu li ul ul {
+       margin: -1.75em 0 0 14em;
+}
+
+#menu li:hover ul ul, #menu li:hover ul ul ul, 
+#menu li.sfhover ul ul, #menu li.sfhover ul ul ul {
+       left: -999em;
+}
+
+#menu li:hover ul, #menu li li:hover ul, #menu li li li:hover ul,
+#menu li.sfhover ul, #menu li li.sfhover ul, #menu li li li.sfhover ul {
+       left: auto;
+}
+
+#menu li:hover, #menu li.sfhover {
+       background: #eeeae6;
+}
+
diff --git a/gui/bweb/html/bweb.js b/gui/bweb/html/bweb.js
new file mode 100644 (file)
index 0000000..72b50e8
--- /dev/null
@@ -0,0 +1,309 @@
+// Bweb - A Bacula web interface
+// Bacula® - The Network Backup Solution
+//
+// Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+//
+// The main author of Bweb is Eric Bollengier.
+// The main author of Bacula is Kern Sibbald, with contributions from
+// many others, a complete list can be found in the file AUTHORS.
+//
+// This program is Free Software; you can redistribute it and/or
+// modify it under the terms of version two of the GNU General Public
+// License as published by the Free Software Foundation plus additions
+// that are listed in the file LICENSE.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA.
+//
+// Bacula® is a registered trademark of John Walker.
+// The licensor of Bacula is the Free Software Foundation Europe
+// (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
+// Switzerland, email:ftf@fsfeurope.org.
+
+ var even_cell_color = "#FFFFFF";
+ var odd_cell_color  = "#EEEEEE";
+ var header_color    = "#E1E0DA";
+ var rows_per_page   = 20;
+ var bweb_root       = "/bweb/";
+ var up_icon         = "/bweb/up.gif";
+ var down_icon       = "/bweb/down.gif";
+ var prev_icon       = "/bweb/left.gif";
+ var next_icon       = "/bweb/right.gif";
+ var rew_icon        = "/bweb/first.gif";
+ var fwd_icon        = "/bweb/last.gif";
+
+ var jobstatus = {
+ 'C': 'created but not yet running',
+ 'R': 'running',
+ 'B': 'blocked',
+ 'T': 'terminated normally',
+ 'E': 'Job terminated in error',
+ 'e': 'Non-fatal error',
+ 'f': 'Fatal error',
+ 'D': 'Verify differences',
+ 'A': 'canceled by user',
+ 'F': 'waiting on File daemon',
+ 'S': 'waiting on the Storage daemon',
+ 'm': 'waiting for new media',
+ 'M': 'waiting for Mount',
+ 's': 'Waiting for storage resource',
+ 'j': 'Waiting for job resource',
+ 'c': 'Waiting for Client resource',
+ 'd': 'Waiting for maximum jobs',
+ 't': 'Waiting for start time',
+ 'p': 'Waiting for higher priority jobs to finish'
+};
+
+var joblevel = {
+ 'F': 'Full backup',
+ 'I': 'Incr (since last backup)',
+ 'D': 'Diff (since last full backup)',
+ 'C': 'verify from catalog',
+ 'V': 'verify save (init DB)',
+ 'O': 'verify Volume to catalog entries',
+ 'd': 'verify Disk attributes to catalog',
+ 'A': 'verify data on volume',
+ 'B': 'Base level job'
+};
+
+
+var refresh_time = 60000;
+
+function bweb_refresh() {
+  location.reload(true)
+}
+function bweb_add_refresh(){
+       window.setInterval("bweb_refresh()",refresh_time);
+}
+
+function human_size(val)
+{   
+   if (!val) {
+      return '';
+   }
+   var unit = ['b', 'Kb', 'Mb', 'Gb', 'Tb'];
+   var i=0;
+   var format;
+   while (val /1024 > 1) {
+      i++;
+      val /= 1024;
+   }
+
+   var format = (i>0)?1:0;
+   return val.toFixed(format) + ' ' + unit[i];
+}
+
+function human_sec(val)
+{
+   if (!val) {
+      val = 0;
+   }
+   val /= 60;                  // sec -> min
+   
+   if ((val / 60) <= 1) {
+      return val.toFixed(0) + ' mins';
+   }
+
+   val /= 60;                  // min -> hour
+
+   if ((val / 24) <= 1) { 
+      return val.toFixed(0) + ' hours';
+   }
+
+   val /= 24;                   // hour -> day
+
+   if ((val / 365) < 2) { 
+      return val.toFixed(0) + ' days';
+   }
+
+   val /= 365;
+
+   return val.toFixed(0) + ' years';
+}
+
+
+//
+// percent_display("row2", [ { nb: 1, name: "Full"   },
+//                        { nb: 2, name: "Error"  },
+//                        { nb: 5, name: "Append" },
+//                        { nb: 2, name: "Purged" },
+//                         {}                               # last element must be {}
+//                      ]);
+
+function percent_get_img(type)
+{
+   var img=document.createElement('img');
+   if (type) {
+      img.className="pSlice" + type ;
+   } else {
+      img.className="pSlice";
+   }
+   img.src="/bweb/pix.png";
+   img.alt="";
+   return img;
+}
+
+var percent_display_nb_slice = 20;
+var percent_usage_nb_slice = 5;
+
+function percent_display(hash_values, parent)
+{
+   var nb_elt=percent_display_nb_slice;
+   var tips= "";
+
+   if (!parent) {
+      parent = document.createElement('DIV');
+   }
+
+   if (typeof parent != "object") {
+      parent = document.getElementById(parent);
+   } 
+
+   if (!parent) {
+       alert("E : display_percent(): Can't find parent " + parent);
+       return;
+   }
+
+   hash_values.pop(); // drop last element {}
+
+   var nb_displayed = 0;
+   var nb_max = 0;
+
+   for(var i=0;i<hash_values.length;i++) {
+        nb_max += hash_values[i]['nb'];
+   }
+
+   for(var i=0;i<hash_values.length;i++) {
+        var elt = hash_values[i];
+        var cur_nb = (elt['nb'] * nb_elt)/nb_max;
+        var cur_name = elt['name'];
+        cur_name.replace(/-/,"_");
+
+        tips = tips + " " + elt['nb'] + " " + cur_name;
+
+        while ((nb_displayed < nb_elt) && (cur_nb >=1)) {
+            nb_displayed++;
+            cur_nb--;
+
+            var img= percent_get_img(cur_name);
+            parent.appendChild(img);
+        }       
+   }
+
+   while (nb_displayed < nb_elt) {
+      nb_displayed++;
+      var img= percent_get_img();
+      parent.appendChild(img);
+  }     
+
+  parent.title = tips;
+
+  return parent;
+}
+
+function percent_usage(value, parent)
+{
+   var nb_elt=percent_usage_nb_slice;
+   var type;
+  
+   if (!parent) {
+      parent = document.createElement('DIV');
+   }   
+
+   if (typeof parent != "object") {
+      parent = document.getElementById(parent);
+   } 
+
+   if (!parent) {
+       alert("E : display_percent(): Can't find parent " + parent);
+       return;
+   }
+
+   if (value <= 0.001) {
+      type = "Empty";
+      value = 0;      
+   } else if (value <= 40) {
+      type = "Ok";
+   } else if (value <= 75) {
+      type = "Warn";
+   } else if (value <= 85) {
+      type = "Crit";
+   } else {
+      type = "Crit";
+   }
+
+   var nb = parseInt(value*nb_elt/100, 10);
+   parent.title = parseInt(value*100,10)/100 + "% used (approximate)";
+
+   for(var i=0; i<nb; i++) {
+      var img= percent_get_img(type);
+      parent.appendChild(img);
+   }
+
+   for(nb;nb < nb_elt;nb++) {
+      var img= percent_get_img("Empty");
+      parent.appendChild(img);       
+   } 
+
+   return parent;
+}
+
+function bweb_get_job_img(status, errors)
+{
+  var ret;
+
+  if (status == "T") {
+     if (errors > 0) {
+        ret = "W.png";
+
+     } else {
+        ret = "T.png";
+     }
+
+  } else {
+     ret = status + ".png";
+  }
+
+  return bweb_root + ret;
+}
+
+function search_media()
+{
+ var what = document.getElementById('searchbox').value;
+ if (what) {
+   document.search.action.value='media';
+   document.search.re_media.value=what;
+   document.search.submit();
+ }
+}
+
+function search_client()
+{
+ var what = document.getElementById('searchbox').value;
+ if (what) {
+   document.search.action.value='client';
+   document.search.re_client.value=what;
+   document.search.submit();
+ }
+}
+
+sfHover = function() {
+ var sfEls = document.getElementById("menu").getElementsByTagName("LI");
+ for (var i=0; i<sfEls.length; i++) {
+    sfEls[i].onmouseover=function() {
+       this.className+=" sfhover";
+    }
+    sfEls[i].onmouseout=function() {
+       this.className=this.className.replace(new RegExp(" sfhover\\b"), "");
+    }
+ }
+}
+
+if (window.attachEvent) window.attachEvent("onload", sfHover);
diff --git a/gui/bweb/html/cancel.png b/gui/bweb/html/cancel.png
new file mode 100644 (file)
index 0000000..89c2124
Binary files /dev/null and b/gui/bweb/html/cancel.png differ
diff --git a/gui/bweb/html/chart.png b/gui/bweb/html/chart.png
new file mode 100644 (file)
index 0000000..333769d
Binary files /dev/null and b/gui/bweb/html/chart.png differ
diff --git a/gui/bweb/html/client.png b/gui/bweb/html/client.png
new file mode 100644 (file)
index 0000000..b2f58c8
Binary files /dev/null and b/gui/bweb/html/client.png differ
diff --git a/gui/bweb/html/colorscm.png b/gui/bweb/html/colorscm.png
new file mode 100644 (file)
index 0000000..cf2ccef
Binary files /dev/null and b/gui/bweb/html/colorscm.png differ
diff --git a/gui/bweb/html/down.gif b/gui/bweb/html/down.gif
new file mode 100755 (executable)
index 0000000..ce294fd
Binary files /dev/null and b/gui/bweb/html/down.gif differ
diff --git a/gui/bweb/html/edit.png b/gui/bweb/html/edit.png
new file mode 100644 (file)
index 0000000..3677539
Binary files /dev/null and b/gui/bweb/html/edit.png differ
diff --git a/gui/bweb/html/extern.png b/gui/bweb/html/extern.png
new file mode 100644 (file)
index 0000000..cfc3b35
Binary files /dev/null and b/gui/bweb/html/extern.png differ
diff --git a/gui/bweb/html/f.png b/gui/bweb/html/f.png
new file mode 100644 (file)
index 0000000..89c2124
Binary files /dev/null and b/gui/bweb/html/f.png differ
diff --git a/gui/bweb/html/favicon.ico b/gui/bweb/html/favicon.ico
new file mode 100644 (file)
index 0000000..d4ead7a
Binary files /dev/null and b/gui/bweb/html/favicon.ico differ
diff --git a/gui/bweb/html/filename.png b/gui/bweb/html/filename.png
new file mode 100644 (file)
index 0000000..7e5776a
Binary files /dev/null and b/gui/bweb/html/filename.png differ
diff --git a/gui/bweb/html/first.gif b/gui/bweb/html/first.gif
new file mode 100755 (executable)
index 0000000..10a4e7e
Binary files /dev/null and b/gui/bweb/html/first.gif differ
diff --git a/gui/bweb/html/first.png b/gui/bweb/html/first.png
new file mode 100644 (file)
index 0000000..5e8aa7a
Binary files /dev/null and b/gui/bweb/html/first.png differ
diff --git a/gui/bweb/html/index.html b/gui/bweb/html/index.html
new file mode 100644 (file)
index 0000000..97894a5
--- /dev/null
@@ -0,0 +1,9 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<HTML>
+<HEAD>
+<META HTTP-EQUIV=Refresh CONTENT="0; URL=/cgi-bin/bweb/bweb.pl">
+</HEAD>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#0000EF" VLINK="#55188A" ALINK="#FF0000">
+</BODY>
+</HTML>
+
diff --git a/gui/bweb/html/inflag0.png b/gui/bweb/html/inflag0.png
new file mode 100644 (file)
index 0000000..6478554
Binary files /dev/null and b/gui/bweb/html/inflag0.png differ
diff --git a/gui/bweb/html/inflag1.png b/gui/bweb/html/inflag1.png
new file mode 100644 (file)
index 0000000..e061e7f
Binary files /dev/null and b/gui/bweb/html/inflag1.png differ
diff --git a/gui/bweb/html/intern.png b/gui/bweb/html/intern.png
new file mode 100644 (file)
index 0000000..64b8300
Binary files /dev/null and b/gui/bweb/html/intern.png differ
diff --git a/gui/bweb/html/kaiska.css b/gui/bweb/html/kaiska.css
new file mode 100644 (file)
index 0000000..a05d89c
--- /dev/null
@@ -0,0 +1,970 @@
+/*
+* ----------------------------------------------------------------------------
+* "THE BEER-WARE LICENSE" (Revision 42):
+* Willy Morin (kaiska@ifrance.com) wrote this file. As long as you retain this
+* notice you can do whatever you want with this stuff. If we meet some day,
+* and you think this stuff is worth it, you can buy me a beer in return
+*
+* Willy Morin
+* http://kaiska.flinkserver.net
+*
+* Addendum Ã‰tienne Bersac ( commentsbrowser ), http://bersace03.free.fr
+* ----------------------------------------------------------------------------
+*/ 
+
+* { font-family: sans-serif, monospace; }
+
+body { background: #f1f1f1; }
+
+a:link {    
+    color: #36598E;
+    text-decoration: none;
+}    
+    
+a:visited {    
+    color: #B64545;
+    text-decoration: none;
+}
+
+h1.rubrique_info {
+    color: #552 !important;  
+    margin: 0px 0px 0px 0px;
+    padding: 0em; 
+    border: 0px;
+    font-size: 12px;
+}
+h1.connexe {
+    font-size: 12px;
+    padding: 0em;
+    margin: 0px 0px 0px 0px;
+    color: #900;
+}
+
+a.rubrique_infolink { text-decoration: none; }
+ul.rubrique_infoul {
+    display: inline;
+    list-style-type: square;
+}
+ul.rubrique_infoul * { width: 100%; }
+li.rubrique_infoul { margin-left: 15px; }
+
+.leftbox ul.rubrique_infoul {
+       display:block;
+       padding: 0 10px 0 10px;
+       margin-right: -10px;
+}
+
+h1 { color: #990033; }
+
+div.main {  
+               margin: 15px 10px 0px 10px;
+    border: 2px #ddd solid;
+    text-align: left;
+    font-size: 0.8em;
+}
+
+div.lsfnbanner {
+       position: absolute;
+       top: 0;
+       left: 4px;
+       width: 99%;
+       text-align: center;
+       font-size: .8em;
+       padding: 0;
+       margin: 0;
+       border: 0;
+}
+
+div.footer {
+       padding-top: 5px;
+       padding-bottom: 3px;
+       border-top: 1px #ccc solid;
+       border-left: 1px #ccc solid;
+       border-right: 1px #ccc solid;
+       text-align: left;
+       font-size: 9px;
+       background: #eeeae6;
+       margin-top: 40px;
+       margin-left: 20px;
+       margin-right: 20px;
+}
+div.footer p {
+       margin-left: 10px;
+       margin-top: 2px;
+       margin-bottom: 2px;
+}
+div.menubartop {
+    margin: 0;
+               padding:0;
+               background:#ddd;
+}
+
+div.smallmenubar {
+    padding: 4px;
+               padding-left: 10px;
+               padding-right: 10em;
+               margin-top: -4px;
+               font-weight: normal;
+    font-size: 0.8em;
+    text-align: left;
+               background: #e0ddd8;
+}
+
+div.smallmenubar a:hover{
+       margin-bottom:4px;
+}
+div.menuevent {
+    float: left;
+    width: 350px;
+    font-size: 11px;
+    text-align: left;
+    padding-top: 0px;
+    padding-bottom: 0px;
+    padding-left: 10px;
+    font-weight: bold;
+    margin: 0px;
+}
+div.menubar {
+    background: #eeeae6;
+    border-top: 1px #999 solid;
+    border-bottom: 1px #999 solid;
+    padding: 2px 10px 3px 10px;
+    font-weight:bold;
+    font-size: 1em;
+}
+div.menubar a {
+       text-decoration: none;
+}
+div.menubar p {
+       padding: 0px;
+       margin: 0px;
+}
+
+.menudate { visibility:hidden;height:0;margin:0;padding:0;}
+
+div.menusearch {
+       float: none;
+       position: absolute;
+       top: 19px;
+       right:22px;
+       margin:0;
+  text-align: left;
+       padding: 0;
+       width: auto;
+       background: transparent url('/bweb/add.png') 2px no-repeat;
+       padding-left:25px;
+}
+div.menusearch p {
+       margin: 0;
+}
+div.newsletter {
+       float: right;
+       text-align: right;
+       margin: 0px;
+       padding: 0px;
+       font-size: 8px;
+       font-weight: normal;
+}
+div.newsletter p { margin: 0px 0px 0px 0px; }
+.searchinput {
+       border: solid 1px #ccc;
+       padding-left: 5px;
+       padding-right: 5px;
+       height:1.1em;
+}
+.searchinput:focus{
+       border: solid 1px #777;
+       background: #f5f5e9;
+       padding-left: 5px;
+       padding-right: 5px;
+}
+
+.newsletterinput {
+    border: solid 1px black;
+    font-weight: normal;
+}
+a#menulinkselect { color: #ed7e00; }
+
+div.leftbox {
+    width: 200px; 
+    float: left; 
+    padding-right: 5px;
+    padding-bottom: 5px;
+    border-right: 0px solid #ccc;
+    border-bottom: 0px solid #ccc;
+    background: white;
+    margin-bottom: 10px;
+    margin-right: 20px;
+    overflow: hidden;
+}
+div.leftbox h1 {
+       text-transform: uppercase;
+       font-weight: bold;
+       color: #ed7e00;
+       font-size: 10px;
+       margin: 0px;
+}
+div.leftbox h2 {
+       font-weight: bold;
+       font-size: 12px;
+       margin: 0px;
+}
+div.leftbox ul {
+  list-style-type: square;
+       color: #552;
+       margin-left: 5px;
+       margin-right: 5px;
+       padding-left: 10px;
+       border: 1px solid #bbb;
+       background: #eeeae6;
+       -moz-border-radius: 10px;
+}
+div.leftbox li {
+       margin-left: 10px;
+       margin-top: 3px;
+       padding-bottom: 3px;
+       border-bottom: 1px solid #ddd;
+       font-size:0.8em;
+}
+
+div.leftbox p {
+       color: #552;
+       text-align:center;
+}
+
+div.rightbox {
+    width: 140px; 
+    float: right; 
+    padding-top: 10px;
+    padding-left: 5px;
+               padding-right: 15px;
+    padding-bottom: 5px;
+    border: 1px solid #ccc;
+               margin: 10px;
+               -moz-border-radius: 10px;
+               text-align: left;
+               background: #eeeae6;
+}
+div.rightbox h1{
+       color: #552;
+}
+
+div.rightbox ul {
+  list-style-type: square;
+       color: #552;
+       padding:0;
+}
+div.rightbox li {
+       margin-left: 10px;
+       margin-top: 3px;
+       padding-bottom: 3px;
+       border-bottom: 1px solid #ddd;
+       font-size:0.8em;
+}
+
+div.journaldiv {
+       margin-left: 0px;
+       margin-right: 0px;
+       margin-top: 20px;
+       margin-bottom: 20px;
+       border: 1px solid #ccc;
+       padding-top: 5px;
+       padding-bottom: 5px;
+       padding-right: 10px;
+       padding-left: 10px;
+       background-color: #eeeae6;
+       -moz-border-radius: 10px;
+}
+div.journaldiv p {
+       margin-top: 10px;
+       margin-bottom: 0px;
+}
+div.journaldiv h1 {
+  color: #552;
+       margin: 0;
+       border-bottom: 1px dotted #bbb;
+}
+div.journaldiv h2 {
+       font-size: 10px;
+       margin: 0;
+}
+div.tipdiv {
+       margin-right: 50px;
+       padding-top: 5px;
+       padding-right: 10px;
+       padding-left: 10px;
+       text-align: justify;
+       background-color: #eee;
+       border: black solid 1px;
+       margin-left: 10px;
+}
+div.tipdiv h1 {
+       font-weight: bold;
+       font-size: 14px;
+       color: black;
+  margin-top: 0;
+  margin-bottom: 20px;
+}
+div.tipdiv h2 {
+       text-transform: uppercase;
+       font-weight: bold;
+       color: #ed7e00;
+       font-size: 12px;
+       margin: 0;
+}
+
+div.newsdiv {
+    margin-left: 220px;
+    margin-right: 180px;
+    margin-top: 10px;
+    margin-bottom: 20px;
+       text-align: justify;
+}
+div.newsdiv h1 {
+       font-weight: bold;
+       font-size: 14px;
+       margin: 0px;
+}
+div.newsdiv h2 {
+       font-weight: normal;
+       font-size: 12px;
+       margin: 0px;
+}
+div.newsdiv h3 {
+       font-weight: normal;
+       font-size: 12px;
+       margin-bottom: 20px;
+}
+div.objdiv {
+    margin-left: 220px;
+    margin-right: 20px;
+    margin-top: 10px;
+    margin-bottom: 20px;
+}
+
+h1.newstitle {
+    text-align: left;
+    font-size: 14px;
+    margin: 0px 0px 0px 0px;
+    color: #552;
+}
+div.titlediv {
+    border-top: solid #cac2a8 0px;
+    margin-top: 20px;
+               padding-top: 5px;
+    background-color: #eeeae6;
+    padding-left: 10px;
+    font-size: 11px;
+               color:#666;
+               -moz-border-radius: 10px 10px 0 0;
+}
+div.bodydiv {
+       border-top: solid #ccc 0px;
+       border-bottom: solid #ccc 1px;
+       border-left: solid #ccc 1px;
+       border-right: solid #ccc 1px;
+       padding-left: 10px;
+  padding-right: 10px;
+       padding-top: 10px;
+       padding-bottom: 5px;
+  margin-top: 0;
+  text-align: justify;
+       background: #f5f5f5;
+       -moz-border-radius: 0 0 10px 10px;
+}
+
+div.comments {
+    padding: 10px;
+    border-top: solid 2px #552;
+    border-bottom: solid 2px #552;
+    border-left: 1px solid #ccc;
+               border-right: 1px solid #ccc;
+               margin-top: 20px;
+    margin-bottom: 10px;
+    background: #dad6d1;
+    font-size: 12px;
+    line-height: 1.3em;
+                       -moz-border-radius: 10px;
+}
+
+.comment-vote { font-style: italic; color:#666; font-size:0.9em;}
+
+p.commentsbody {
+  border-left: 1px solid #aaa;
+  padding-left: 10px;
+       text-align: justify;
+       margin-right: 20px;
+}
+div.commentsreply {
+       text-align: center;
+       margin-top: 10px;
+       font-size:0.9em;
+       color: #666;
+}
+
+div.commentsreply .searchinput{ height:auto; }
+
+ul.commentsul {
+  list-style-type: none;
+       margin-bottom: 10px;
+       margin-left: 1.25em;
+       padding-left: 0;
+}
+ul.commentsli { margin: 10px; }
+div.comments li {
+       margin-top: 20px;
+       margin-left: 2px;
+}
+
+div.comments h1 {
+    font-size: 12px;
+    color: black;
+    margin: 0px 20px 3px 0px;
+               background:#ebe7e2;
+    padding-left: 1px;
+    font-weight: normal;
+               -moz-border-radius: 10px;
+}
+
+div.articlediv {
+    padding-left: 20px;
+    padding-right: 20px;
+    padding-top: 10px;
+    padding-bottom: 20px;
+    margin-right: 180px;
+    margin-left: 220px;
+    margin-top: 10px;
+    text-align: justify;
+    background: #dad6d1;
+               -moz-border-radius: 10px;
+               border: 1px solid #ccc;
+}
+img { border: 0; }
+div.sectionimg {
+    float: left;
+    margin-right: 10px;
+    margin-top: 5px;
+}
+p.hautpage {
+       margin-top: 20px;
+       margin-bottom: 20px;
+       margin-left: 10px;
+}
+div.leftcol {
+       width: 202px;
+       float: left;
+       padding: 0px;
+}
+div.logodiv {
+       border-right: 0px black solid;
+       border-bottom: 0px black solid;
+       padding: 0px;
+       line-height: 0px
+}
+div.loginbox {
+       margin-left: 4px;
+       border: solid #bbb 1px;
+       margin-top: 5px;
+       padding: 5px;
+       background-color: #E0DDD8;
+       font-size: 0.8em;
+       -moz-border-radius: 10px;
+}
+div.loginbox p {
+       margin: 0px;
+       padding: 0px;
+}
+div.loginbox ul {
+       margin-left: 2px;
+       margin-top: 0px;
+       margin-bottom: 0px;
+       padding: 0px;
+  list-style-type: none;
+       border-left: 1px solid #aaa;
+       padding-left: 8px;
+}
+div.loginbox h1 {
+       text-transform: none;
+       font-weight: bold;
+       color: #552;
+       font-size: 1.2em;
+       margin: 0px;
+       margin-top:10px;
+       border-bottom:1px solid #ccc;
+}
+div.loginbox h2 {
+       font-weight: bold;
+       font-size: 1.1em;
+       margin: 0px;
+}
+div.loginbox h3 {
+       margin-top: 0px;
+       margin-bottom: 5px;
+       font-size: 12px;
+}
+#poll div.otherbox ul {
+       margin-left: 0px;
+       margin-top: 0px;
+       margin-bottom: 10px;
+       padding: 0px;
+       list-style-type: none;
+}
+div.otherboxtitle {
+       margin-bottom: 2px;
+       background-color: #e0ddd8;
+       margin-left: 4px;
+       margin-top: 5px;
+       margin-bottom: 0px;
+       padding-left: 5px;
+       padding-top: 2px;
+       font-size: 11px;
+       border-top: 1px solid #ccc;
+       border-bottom: 0px solid #ccc;
+       font-size: 1em;
+       font-weight: bold;
+       -moz-border-radius: 10px 10px 0px 0px;
+       text-transform: none;
+}
+div.otherbox {
+       margin-left: 4px;
+       border: 1px #ccc solid;
+       border-top:0px;
+       margin-top: 0px;
+       padding: 5px;
+       text-align: left;
+       background: #e0ddd8;
+       font-size: 10px;
+       -moz-border-radius: 0px 0px 10px 10px;
+}
+div.otherbox h1 {
+       text-transform: uppercase;
+       font-weight: bold;
+       color: #552;
+       font-size: 1.2em;
+       margin: 0px;
+       text-transform: none;
+       border-bottom: 1px dotted #ccc;
+}
+div.otherbox h2 {
+       font-weight: bold;
+       font-size: 11px;
+       margin: 0px;
+}
+div.otherbox p {
+       margin-top: 5px;
+       margin-bottom: 10px;
+}
+div.rightlogo { 
+    width: 90px; 
+    float: right;
+    margin-right: 0px;
+    padding-top: 0px;
+    padding-left: 0px;
+    padding-bottom: 0px;
+}   
+div.centraldiv {
+  margin-left: 220px;
+  margin-right: 10px;
+  margin-bottom: 20px;
+       margin-top: 10px;
+}
+div.centraldiv h1 {
+       font-weight: bold;
+       font-size: 14px;
+       margin: 0px;
+}
+div.centraldiv h2 {
+       font-weight: normal;
+       font-size: 12px;
+       margin: 0px;
+}
+div.centraldiv h3 {
+       font-weight: normal;
+       font-size: 12px;
+       margin-bottom: 20px;
+}
+div.lefttopbox {
+       padding: 5px;
+       border: 2px #ddd solid;
+       text-align: justify;
+       background: #f9f9f9;
+       font-size: 0.8em;
+       float: left;
+       -moz-border-radius: 10px;
+}
+div.lefttopbox p {     margin-top: 5px; margin-bottom: 10px; }
+div.lefttopbox h1 {
+       font-size: 0px;
+       font-weight: bold;
+       margin: 0px;
+       text-align: right;
+}
+div.lefttopbox h2 {
+       text-transform: uppercase;
+       font-weight: bold;
+       color: #ed7e00;
+       font-size: 13px;
+       margin: 0px;
+}
+div.lefttopbox h3 {
+       font-weight: bold;
+       font-size: 1.1em;
+       text-align:left;
+       margin: 0px;
+}
+div.righttopbox {
+       border: 1px #ccc solid;
+       background: white;
+       padding: 5px;
+       text-align: justify;
+       font-size: 0.8em;
+       width: 34%;
+       float: right;
+       -moz-border-radius: 10px;
+}
+div.righttopbox h1 {
+       text-transform:none;
+       font-weight: bold;
+       font-size: 10px;
+       margin: 0px;
+       color: #552;
+       border-bottom: 1px solid #ccc;
+}
+div.righttopbox h2 {
+       font-weight: bold;
+       font-size: 1.1em;
+       color: #666;
+       margin: 0px;
+}
+div.boardindex {
+       text-align: justify;
+       font-size: 11px;
+       padding: 10px;
+       margin-left: 20px;
+       margin-right: 20px;
+}
+a.boardindex:link,a.boardindex:visited,a.boardindex:active {
+       text-decoration:none;
+       color: red;
+}
+div.boardleftmsg {
+       float: left;
+       margin-top: 3px;
+}
+div.boardrightmsg {
+       margin-left: 130px;
+       margin-top: 3px;
+       padding-left: 5px;
+}
+div.journalbody {
+       margin-left: 40px;
+       margin-top: 40px;
+}
+div.journalbody h1 {
+       font-size: 15px;
+       font-weight: bold;
+}
+div.journalbody p {
+       margin-bottom: 20px;
+}
+.formulaire {
+    border: solid 1px black;
+font-size: 12px;
+background-color: #fffbf7;
+color: #000000;
+}
+
+.newcomments {
+       color: red;
+       font-weight: bold;
+}
+div.commentsreplythanks {
+       margin-left: 100px;
+       margin-top: 50px;
+       margin-right: 100px;
+       background-color: #eee;
+       border: black solid 1px;
+       padding: 10px;
+}
+div.archivediv { margin-right: 20px; }
+.archivedate { color:#f30; }
+.archivelink {
+       font-size: 14px;
+       font-weight: bold;
+       text-decoration: underline;
+}
+div.forumgroup {
+       text-align: left;
+       border: solid black 1px;
+       padding: 10px 20px 20px 10px;
+       background-color: #eeeae6;
+       border: 1px solid #ccc;
+       -moz-border-radius: 10px;
+}
+
+div.forumgroup b{
+       color: #552;
+       background: #e0ddd8;
+       font-size: 1.1em;
+       display:block;
+       -moz-border-radius: 10px;
+       padding-left: 10px;
+       padding-right: 10px;
+       margin-left:-15px;
+       margin-right:-15px;
+       margin-top:-3px;
+}
+
+div.forumgroup td{
+       -moz-border-radius: 10px;
+}
+
+div.adminall {
+       font-size: 12px;
+       padding: 10px;
+}
+div.floatwin {
+    position:absolute;
+    top: 150px;
+    left: 450px;
+    width:200px;
+    visibility:hidden;
+    background: #dcdff4;
+    padding: 5px;
+    border: solid black 1px;
+}
+
+div.poll-result-bar {
+       background: #eeeae6;
+       color: black;
+       border: solid 1px #ccc;
+       font-size: 0.7em;
+       -moz-border-radius: 10px;
+}
+div.funbanner {
+       text-align: right;
+       border-top: #aaa solid 1px;
+       border-bottom: #aaa solid 1px;
+       padding-right: 20px;
+       padding-top: 2px;
+       padding-bottom: 2px;
+       font-size: 10px;
+       background-color: #fff2e8;
+       font-weight: bold;
+       margin-top: 10px;
+}
+
+div.main
+{
+       margin-bottom: 3em !important;
+}
+
+.replie
+{
+       display: none;  
+}
+
+.deplie
+{
+       display: block;
+}
+
+#commentsnav
+{
+       display: none;
+       text-align: right;
+}
+
+#commentsbrowser
+{
+  border: 1px solid #baa !important;
+  background: #dfd6d1 !important;
+  color: #333333;
+  position: fixed;
+  bottom: 0.5ex;
+  max-height: 0.8ex;
+  padding: 2px 0 0;
+  overflow: hidden;
+  left: 19px !important;
+  right: 19px !important;
+  font-size: 10px;
+}
+
+#commentsbrowser:hover
+{ 
+  max-height: none;
+  padding: 0.5ex;
+  overflow: hidden;
+}
+
+div.comments h1.nouveau
+{
+       border: 1px solid rgb(211, 117, 55);
+       /*border: 1px solid #D58E64;*/
+       background-color: rgb(225, 220, 220);
+       
+       color: #111111;
+}
+
+#pallierdiv, #csspersodiv
+{
+       position: fixed;
+       bottom: 5em;
+       left: 3%;
+       max-width: 17em;
+       border: 1px solid #333333;
+       background: #EEEEEE;
+       color: #333333;
+       padding: 0.6em;
+       display: none;
+}
+
+#csspersodiv
+{
+       left: 37%;
+       max-width: 35em;
+}
+
+#pallierdiv input, #csspersodiv input
+{
+       margin-left: 0.2em;
+}
+
+form
+{
+       margin: 0;
+}
+
+#cssurl
+{
+       width: 12em;
+}
+
+#pallierdiv h3, #csspersodiv h3
+{
+    font-size: 12px;
+    padding: 0;
+    margin: 0 0 0.5em 0;
+    color: #990033;
+}
+
+tt 
+{
+       font-size: 1em;
+       background:#fffbec;
+       color: #330;
+}
+               
+pre, code, blockquote,quote
+{
+       font-size: 1em;
+       display:block;
+       background:#fffbec;
+       margin: 5px 15px 5px 15px;
+       padding: 5px;
+       border-left: 1px solid #552;
+       color: #330;
+}
+
+tt, pre, code
+{
+       font-family: "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;
+}
+
+blockquote {   font-style:italic; }
+
+div.titledivmini {
+    border-top: solid #cac2a8 0px;
+               padding-top: 5px;
+    background-color: #eeeae6;
+    padding-left: 10px;
+               color:#666;
+               -moz-border-radius: 10px 10px 0 0;
+}
+h1.newstitlemini {
+    text-align: left;
+    margin: 0px 0px 0px 0px;
+    color: #552;
+               font-size: 12px !important;
+}
+div.subtitlemini {
+    border-top: solid #cac2a8 0px;
+    margin-top: 0px;
+               padding-top: 5px;
+    background-color: #eeeae6;
+    padding-left: 1px;
+    font-size: 11px;
+               color:#666;
+}
+div.bodydivmini {
+       border-top: solid #ccc 0px;
+       border-bottom: solid #ccc 1px;
+       border-left: solid #ccc 1px;
+       border-right: solid #ccc 1px;
+       padding-left: 2px;
+  padding-right: 2px;
+       padding-top: 1px;
+       padding-bottom: 1px;
+  margin-top: 0;
+  margin-bottom: 2px;
+  text-align: justify;
+       background: #f5f5f5;
+       font-size: 11px;
+       -moz-border-radius: 0 0 10px 10px;
+}
+
+blockquote:before {
+       content: "\00AB";
+       font-size:1.3em;
+       font-weight: bold;
+       color: #552;
+}
+
+blockquote:after {
+       content: "\00BB";
+       font-size:1.3em;
+       font-weight: bold;
+       color: #552;
+}
+
+em{ font-style: italic; }
+
+#palliercontainer {
+      text-align: left;
+      margin-left: 20px;
+}
+
+#csscourantecontainer {
+      text-align: center;
+      padding-left: 20%;
+}
+
+#newcommentsnav {
+      float: right;
+      text-align: right;
+}
+
+.centraldiv table {
+border: 0;
+}
+.centraldiv table td {
+border: thin solid #BBBBBB;
+background:#E0DDD8;
+}
+
+.centraldiv table th {
+padding:1em;
+background:#CCCCCC;
+border:0;
+border-top:1em solid white;
+}
+
+div.extrait {
+visibility:hidden;
+position:fixed;
+bottom:1em;
+right:1em;
+left:1em;
+background:#E0DDD8;
+border:thin solid #BBBBBB;
+}
diff --git a/gui/bweb/html/label.png b/gui/bweb/html/label.png
new file mode 100644 (file)
index 0000000..23a5f7c
Binary files /dev/null and b/gui/bweb/html/label.png differ
diff --git a/gui/bweb/html/last.gif b/gui/bweb/html/last.gif
new file mode 100755 (executable)
index 0000000..986868c
Binary files /dev/null and b/gui/bweb/html/last.gif differ
diff --git a/gui/bweb/html/last.png b/gui/bweb/html/last.png
new file mode 100644 (file)
index 0000000..81303ad
Binary files /dev/null and b/gui/bweb/html/last.png differ
diff --git a/gui/bweb/html/lcorner.png b/gui/bweb/html/lcorner.png
new file mode 100644 (file)
index 0000000..068aed6
Binary files /dev/null and b/gui/bweb/html/lcorner.png differ
diff --git a/gui/bweb/html/left.gif b/gui/bweb/html/left.gif
new file mode 100755 (executable)
index 0000000..c9d91e3
Binary files /dev/null and b/gui/bweb/html/left.gif differ
diff --git a/gui/bweb/html/left.png b/gui/bweb/html/left.png
new file mode 100644 (file)
index 0000000..4fa61ea
Binary files /dev/null and b/gui/bweb/html/left.png differ
diff --git a/gui/bweb/html/load.png b/gui/bweb/html/load.png
new file mode 100644 (file)
index 0000000..493e149
Binary files /dev/null and b/gui/bweb/html/load.png differ
diff --git a/gui/bweb/html/lock.png b/gui/bweb/html/lock.png
new file mode 100644 (file)
index 0000000..9c46dbb
Binary files /dev/null and b/gui/bweb/html/lock.png differ
diff --git a/gui/bweb/html/natcompare.js b/gui/bweb/html/natcompare.js
new file mode 100755 (executable)
index 0000000..2f99489
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+natcompare.js -- Perform 'natural order' comparisons of strings in JavaScript.
+Copyright (C) 2005 by SCK-CEN (Belgian Nucleair Research Centre)
+Written by Kristof Coomans <kristof[dot]coomans[at]sckcen[dot]be>
+
+Based on the Java version by Pierre-Luc Paour, of which this is more or less a straight conversion.
+Copyright (C) 2003 by Pierre-Luc Paour <natorder@paour.com>
+
+The Java version was based on the C version by Martin Pool.
+Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au>
+
+This software is provided 'as-is', without any express or implied
+warranty.  In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+claim that you wrote the original software. If you use this software
+in a product, an acknowledgment in the product documentation would be
+appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be
+misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+
+function isWhitespaceChar(a)
+{
+    var charCode;
+    charCode = a.charCodeAt(0);
+
+    if ( charCode <= 32 )
+    {
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+function isDigitChar(a)
+{
+    var charCode;
+    charCode = a.charCodeAt(0);
+
+    if ( charCode >= 48  && charCode <= 57 )
+    {
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+function compareRight(a,b)
+{
+    var bias = 0;
+    var ia = 0;
+    var ib = 0;
+
+    var ca;
+    var cb;
+
+    // The longest run of digits wins.  That aside, the greatest
+    // value wins, but we can't know that it will until we've scanned
+    // both numbers to know that they have the same magnitude, so we
+    // remember it in BIAS.
+    for (;; ia++, ib++) {
+        ca = a.charAt(ia);
+        cb = b.charAt(ib);
+
+        if (!isDigitChar(ca)
+                && !isDigitChar(cb)) {
+            return bias;
+        } else if (!isDigitChar(ca)) {
+            return -1;
+        } else if (!isDigitChar(cb)) {
+            return +1;
+        } else if (ca < cb) {
+            if (bias == 0) {
+                bias = -1;
+            }
+        } else if (ca > cb) {
+            if (bias == 0)
+                bias = +1;
+        } else if (ca == 0 && cb == 0) {
+            return bias;
+        }
+    }
+}
+
+function natcompare(a,b) {
+
+    var ia = 0, ib = 0;
+       var nza = 0, nzb = 0;
+       var ca, cb;
+       var result;
+
+    while (true)
+    {
+        // only count the number of zeroes leading the last number compared
+        nza = nzb = 0;
+
+        ca = a.charAt(ia);
+        cb = b.charAt(ib);
+
+        // skip over leading spaces or zeros
+        while ( isWhitespaceChar( ca ) || ca =='0' ) {
+            if (ca == '0') {
+                nza++;
+            } else {
+                // only count consecutive zeroes
+                nza = 0;
+            }
+
+            ca = a.charAt(++ia);
+        }
+
+        while ( isWhitespaceChar( cb ) || cb == '0') {
+            if (cb == '0') {
+                nzb++;
+            } else {
+                // only count consecutive zeroes
+                nzb = 0;
+            }
+
+            cb = b.charAt(++ib);
+        }
+
+        // process run of digits
+        if (isDigitChar(ca) && isDigitChar(cb)) {
+            if ((result = compareRight(a.substring(ia), b.substring(ib))) != 0) {
+                return result;
+            }
+        }
+
+        if (ca == 0 && cb == 0) {
+            // The strings compare the same.  Perhaps the caller
+            // will want to call strcmp to break the tie.
+            return nza - nzb;
+        }
+
+        if (ca < cb) {
+            return -1;
+        } else if (ca > cb) {
+            return +1;
+        }
+
+        ++ia; ++ib;
+    }
+}
+
diff --git a/gui/bweb/html/next.png b/gui/bweb/html/next.png
new file mode 100644 (file)
index 0000000..1a21626
Binary files /dev/null and b/gui/bweb/html/next.png differ
diff --git a/gui/bweb/html/nrs_table.js b/gui/bweb/html/nrs_table.js
new file mode 100755 (executable)
index 0000000..4f731a4
--- /dev/null
@@ -0,0 +1,1073 @@
+/**
+ * Copyright 2005 New Roads School
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/**
+ * \class nrsTable
+ * This describes the nrsTable, which is a table created in JavaScript that is
+ * able to be sorted and displayed in different ways based on teh configuration
+ * parameters passed to it. 
+ * to create a new table one only needs to call the setup function like so:
+ * <pre>
+ * nrsTable.setup(
+ * {
+ *     table_name: "table_container",
+ *     table_data: d,
+ *     table_header: h
+ * }
+ * );
+ * </pre>
+ * Where table_name is the name of the table to build.  THis must be defined in
+ * your HTML by putting a table declaration, such as <table id=table_name>
+ * </table>.  This will declare where your table will be shown.
+ * All sorts of parameters can be customized here.  For details look at the
+ * function setup.
+ * \see setup
+ */
+
+
+/**
+ * Debug function.  Set debug to tru to view messages.
+ * \param msg Message to display in an alert.
+ */
+debug = false;
+function DEBUG(msg)
+{
+       if(debug)
+               alert(msg);
+}
+
+/**
+ * There is a memory leak problem that I can't seem to fix.  I'm attching 
+ * something that I found from Aaron Boodman, which will clean up all the
+ * memory leaks in the page (this can be found at http://youngpup.net/2005/0221010713
+ * ). This is a little clunky, but it will do till I track this problem.
+ * Oh, and this problem only occurrs is IE.
+ */
+if (window.attachEvent) {
+    var clearElementProps = [
+               'data',
+        'onmouseover',
+        'onmouseout',
+        'onmousedown',
+        'onmouseup',
+        'ondblclick',
+        'onclick',
+        'onselectstart',
+        'oncontextmenu'
+    ];
+
+    window.attachEvent("onunload", function() {
+        var el;
+        for(var d = document.all.length;d--;){
+            el = document.all[d];
+            for(var c = clearElementProps.length;c--;){
+                el[clearElementProps[c]] = null;
+            }
+        }
+    });
+}
+
+
+/**
+ * This is the constructor.
+ * It only needs the name of the table.  This should never be called directly, 
+ * instead use setup function.
+ * \param table The name of the table to create.
+ * \see setup
+ */
+function nrsTable(table)
+{
+       this.my_table = table;
+       this.field_to_sort = 0;
+       this.field_asc = true;
+}
+
+new nrsTable('');
+/**
+ * This function is responsible for setting up an nrsTable.  All the parameters
+ * can be configured directly from this function.  The params array of this 
+ * function is a class (or a associative array, depending on how you want to
+ * look at it) with the following possible parameters:
+ *     - table_name: required.  The id of the table tag.
+ *     - table_header: required.  An array containing the header names.
+ *     - table_data: optional.  A 2D array of strings containing the cell contents.
+ *     - caption: optional.  A caption to include on the table.
+ *     - row_links: optional.  An array with hyperlinks per row.  Must be a javascript function.
+ *     - cell_links: optional.  A 2D array with links on every cell.  Must be a javascript function
+ *     - up_icon: optional.  A path to the ascending sort arrow.
+ *     - down_icon: optional.  A path to the descending sort arrow.
+ *     - prev_icon: optional.  A path to the previous page icon in the navigation.
+ *     - next_icon: optional.  A path to the next page icon in the navigation.
+ *     - rew_icon: optional.  A path to the first page icon in the navigation.
+ *     - fwd_icon: optional.  A path to the last page icon in the navigation.
+ *     - rows_per_page: optional.  The number of rows per page to display at any one time.
+ *     - display_nav: optional.  Displays navigation (prev, next, first, last)
+ *     - foot_headers: optional.  Whether to display th eheaders at the foot of the table.
+ *     - header_color: optional.  The color of the header cells.  Will default to whatever is defined in CSS.
+ *     - even_cell_color: optional.  The color of the even data cells.  Will default to whatever is defined in CSS.
+ *     - odd_cell_color: optional.  The color of the odd data cells.  Will default to whatever is defined in CSS.
+ *     - footer_color: optional.  The color of the footer cells.  Will default to whatever is defined in CSS.
+ *     - hover_color: optional.  The color tha a row should turn when the mouse is over it.
+ *     - padding: optional.  Individual cell padding, in pixels.
+ *     - natural_compare: optional.  Uses the natural compare algorithm (separate from this program) to sort.
+ *     - disable_sorting: optional.  An array specifying the columns top disable sorting on (0 is the first column).
+ *
+ * \params params An array as described above.
+ */
+nrsTable.setup = function(params)
+{
+       //here we assign all the veriables that we are passed, or the defaults if 
+       //they are not defined.
+       //Note that the only requirements are a table name and a header.
+       if(typeof params['table_name'] == "undefined")
+       {
+               alert("Error! You must supply a table name!");
+               return null;
+       }
+       if(typeof params['table_header'] == "undefined")
+       {
+               alert("Error! You must supply a table header!");
+               return null;
+       }
+       
+       //check if the global array exists, else create it.
+       if(typeof(nrsTables) == "undefined")
+       {
+               eval("nrsTables = new Array();");
+       }
+       nrsTables[params['table_name']] = new nrsTable(params['table_name']);
+       nrsTables[params['table_name']].heading = params['table_header'].concat();
+       
+       //now the non-required elements.  Data elements first
+       nrsTables[params['table_name']].data = (typeof params['table_data'] == "undefined" || !params['table_data'])? null: params['table_data'].concat();
+       nrsTables[params['table_name']].caption = (typeof params['caption'] == "undefined")? null: params['caption'];
+       nrsTables[params['table_name']].row_links = (typeof params['row_links'] == "undefined" || !params['row_links'])? null: params['row_links'].concat();
+       nrsTables[params['table_name']].cell_links = (typeof params['cell_links'] == "undefined" || !params['row_links'])? null: params['cell_links'].concat();
+       
+       //these are the icons.
+       nrsTables[params['table_name']].up_icon = (typeof params['up_icon'] == "undefined")? "up.gif": params['up_icon'];
+       nrsTables[params['table_name']].down_icon = (typeof params['down_icon'] == "undefined")? "down.gif": params['down_icon'];
+       nrsTables[params['table_name']].prev_icon = (typeof params['prev_icon'] == "undefined")? "left.gif": params['prev_icon'];
+       nrsTables[params['table_name']].next_icon = (typeof params['next_icon'] == "undefined")? "right.gif": params['next_icon'];
+       nrsTables[params['table_name']].rew_icon = (typeof params['rew_icon'] == "undefined")? "first.gif": params['rew_icon'];
+       nrsTables[params['table_name']].fwd_icon = (typeof params['fwd_icon'] == "undefined")? "last.gif": params['fwd_icon'];
+       
+       //now the look and feel options.
+       nrsTables[params['table_name']].rows_per_page = (typeof params['rows_per_page'] == "undefined")? -1: params['rows_per_page'];
+       nrsTables[params['table_name']].page_nav = (typeof params['page_nav'] == "undefined")? false: params['page_nav'];
+       nrsTables[params['table_name']].foot_headers = (typeof params['foot_headers'] == "undefined")? false: params['foot_headers'];
+       nrsTables[params['table_name']].header_color = (typeof params['header_color'] == "undefined")? null: params['header_color'];
+       nrsTables[params['table_name']].even_cell_color = (typeof params['even_cell_color'] == "undefined")? null: params['even_cell_color'];
+       nrsTables[params['table_name']].odd_cell_color = (typeof params['odd_cell_color'] == "undefined")? null: params['odd_cell_color'];
+       nrsTables[params['table_name']].footer_color = (typeof params['footer_color'] == "undefined")? null: params['footer_color'];
+       nrsTables[params['table_name']].hover_color = (typeof params['hover_color'] == "undefined")? null: params['hover_color'];
+       nrsTables[params['table_name']].padding = (typeof params['padding'] == "undefined")? null: params['padding'];
+       nrsTables[params['table_name']].natural_compare = (typeof params['natural_compare'] == "undefined")? false: true;
+       nrsTables[params['table_name']].disable_sorting = 
+               (typeof params['disable_sorting'] == "undefined")? false: "." + params['disable_sorting'].join(".") + ".";
+       //finally, build the table
+       nrsTables[params['table_name']].buildTable();
+};
+
+
+/**
+ * This is the Javascript quicksort implementation.  This will sort the 
+ * this.data and the this.data_nodes based on the this.field_to_sort parameter.
+ * \param left The left index of the array.
+ * \param right The right index of the array
+ */
+nrsTable.prototype.quickSort = function(left, right)
+{
+       if(!this.data || this.data.length == 0)
+               return;
+//     alert("left = " + left + " right = " + right);
+       var i = left;
+       var j = right;
+       var k = this.data[Math.round((left + right) / 2)][this.field_to_sort];
+       if (k != '') {
+           if (isNaN(k)) {
+             k = k.toLowerCase();
+           } else {
+            k = parseInt(k, 10);
+          }
+        }
+
+       while(j > i)
+       {
+               if(this.field_asc)
+               {
+                       while(this.data[i][this.field_to_sort].toLowerCase() < k)
+                               i++;
+                       while(this.data[j][this.field_to_sort].toLowerCase() > k)
+                               j--;
+               }
+               else
+               {
+                       while(this.data[i][this.field_to_sort].toLowerCase() > k)
+                               i++;
+                       while(this.data[j][this.field_to_sort].toLowerCase() < k)
+                               j--;
+               }
+               if(i <= j )
+               {
+                       //swap both values
+                       //sort data
+                       var temp = this.data[i];
+                       this.data[i] = this.data[j];
+                       this.data[j] = temp;
+                       
+                       //sort contents
+                       var temp = this.data_nodes[i];
+                       this.data_nodes[i] = this.data_nodes[j];
+                       this.data_nodes[j] = temp;
+                       i++;
+                       j--;
+               }
+       }
+       if(left < j)
+               this.quickSort(left, j);
+       if(right > i)
+               this.quickSort(i, right);
+}
+
+/**
+ * This is the Javascript natural sort function.  Because of some obscure JavaScript
+ * quirck, we could not do quicsort while calling natcompare to compare, so this
+ * function will so a simple bubble sort using the natural compare algorithm.
+ */
+nrsTable.prototype.natSort = function()
+{
+       if(!this.data || this.data.length == 0)
+               return;
+       var swap;
+       for(i = 0; i < this.data.length - 1; i++)
+       {
+               for(j = i; j < this.data.length; j++)
+               {
+                       if(!this.field_asc)
+                       {
+                               if(natcompare(this.data[i][this.field_to_sort].toLowerCase(), 
+                                       this.data[j][this.field_to_sort].toLowerCase()) == -1)
+                                       swap = true;
+                               else
+                                       swap = false;
+                       }
+                       else
+                       {
+                               if(natcompare(this.data[i][this.field_to_sort].toLowerCase(), 
+                                       this.data[j][this.field_to_sort].toLowerCase()) == 1)
+                                       swap = true;
+                               else
+                                       swap = false;
+                       }
+                       if(swap)
+                       {
+                               //swap both values
+                               //sort data
+                               var temp = this.data[i];
+                               this.data[i] = this.data[j];
+                               this.data[j] = temp;
+                               
+                               //sort contents
+                               var temp = this.data_nodes[i];
+                               this.data_nodes[i] = this.data_nodes[j];
+                               this.data_nodes[j] = temp;
+                       }
+               }
+       }
+}
+
+/**
+ * This function will recolor all the the nodes to conform to the alternating 
+ * row colors.
+ */
+nrsTable.prototype.recolorRows = function()
+{
+       if(this.even_cell_color || this.odd_cell_color)
+       {
+               DEBUG("Recoloring Rows. length = " + this.data_nodes.length);
+               for(var i = 0; i < this.data_nodes.length; i++)
+               {
+                       if(i % 2 == 0)
+                       {
+                               if(this.even_cell_color)
+                                       this.data_nodes[i].style.backgroundColor = this.even_cell_color;
+                               this.data_nodes[i].setAttribute("id", "even_row");
+                       }
+                       else
+                       {
+                               if(this.odd_cell_color)
+                                       this.data_nodes[i].style.backgroundColor = this.odd_cell_color;
+                               this.data_nodes[i].setAttribute("id", "odd_row");
+                       }
+               }
+       }
+}
+
+/**
+ * This function will create the Data Nodes, which are a reference to the table
+ * rows in the HTML.
+ */
+nrsTable.prototype.createDataNodes = function()
+{
+       if(this.data_nodes)
+               delete this.data_nodes;
+       this.data_nodes = new Array();
+       if(!this.data)
+               return;
+       for(var i = 0; i < this.data.length; i++)
+       {
+               var curr_row = document.createElement("TR");
+               
+               for(var j = 0; j < this.data[i].length; j++)
+               {
+                       var curr_cell = document.createElement("TD");
+                       //do we need to create links on every cell?
+                       if(this.cell_links)
+                       {
+                               var fn = new Function("", this.cell_links[i][j]);
+                               curr_cell.onclick = fn;
+                               curr_cell.style.cursor = 'pointer';
+                       }
+                       //workaround for IE
+                       curr_cell.setAttribute("className", "dataTD" + j);
+                       //assign the padding
+                       if(this.padding)
+                       {
+                               curr_cell.style.paddingLeft = this.padding + "px";
+                               curr_cell.style.paddingRight = this.padding + "px";
+                       }
+                       
+                       if (typeof this.data[i][j] == "object") {
+                               curr_cell.appendChild(this.data[i][j]);
+                       } else {
+                               curr_cell.appendChild(document.createTextNode(this.data[i][j]));
+                       }
+
+                       curr_row.appendChild(curr_cell);
+               }
+               //do we need to create links on every row?
+               if(!this.cell_links && this.row_links)
+               {
+                       var fn = new Function("", this.row_links[i]);
+                       curr_row.onclick = fn;
+                       curr_row.style.cursor = 'pointer';
+               }
+               //sets the id for odd and even rows.
+               if(i % 2 == 0)
+               {
+                       curr_row.setAttribute("id", "even_row");
+                       if(this.even_cell_color)
+                               curr_row.style.backgroundColor = this.even_cell_color;
+               }
+               else
+               {
+                       curr_row.setAttribute("id", "odd_row");
+                       if(this.odd_cell_color)
+                               curr_row.style.backgroundColor = this.odd_cell_color;
+               }
+               if(this.hover_color)
+               {
+                       curr_row.onmouseover = new Function("", "this.style.backgroundColor='" + this.hover_color + "';");
+                       curr_row.onmouseout = new Function("", "this.style.backgroundColor=(this.id=='even_row')?'" + 
+                                                               this.even_cell_color + "':'" + this.odd_cell_color + "';");
+               }
+               this.data_nodes[i] = curr_row;
+       }
+}
+
+/**
+ * This function will update the nav page display.
+ */
+nrsTable.prototype.updateNav = function()
+{
+       if(this.page_nav)
+       {
+               var p = 0;
+               if(this.foot_headers)
+                       p++;
+               var t = document.getElementById(this.my_table);
+               var nav = t.tFoot.childNodes[p];
+               if(nav)
+               {
+                       var caption = t.tFoot.childNodes[p].childNodes[0].childNodes[2];
+                       caption.innerHTML = "Page " + (this.current_page + 1) + " of " + this.num_pages;
+               }
+               else
+               {
+                       if(this.num_pages > 1)
+                       {
+                               this.insertNav();
+                               nav = t.tFoot.childNodes[p];
+                       }
+               }
+               if(nav)
+               {
+                       if(this.current_page == 0)
+                               this.hideLeftArrows();
+                       else
+                               this.showLeftArrows();
+                       
+                       if(this.current_page + 1 == this.num_pages)
+                               this.hideRightArrows();
+                       else
+                               this.showRightArrows();
+               }
+       }
+}
+
+/**
+ * This function will flip the sort arrow in place.  If a heading is used in the
+ * footer, then it will flip that one too.
+ */
+nrsTable.prototype.flipSortArrow = function()
+{
+       this.field_asc = !this.field_asc;
+       //flip the arrow on the heading.
+       var heading = document.getElementById(this.my_table).tHead.childNodes[0].childNodes[this.field_to_sort];
+       if(this.field_asc)
+               heading.getElementsByTagName("IMG")[0].setAttribute("src", this.up_icon);
+       else
+               heading.getElementsByTagName("IMG")[0].setAttribute("src", this.down_icon);
+       //is there a heading in the footer?
+       if(this.foot_headers)
+       {
+               //yes, so flip that arrow too.
+               var footer = document.getElementById(this.my_table).tFoot.childNodes[0].childNodes[this.field_to_sort];
+               if(this.field_asc)
+                       footer.getElementsByTagName("IMG")[0].setAttribute("src", this.up_icon);
+               else
+                       footer.getElementsByTagName("IMG")[0].setAttribute("src", this.down_icon);
+       }
+}
+
+/**
+ * This function will move the sorting arrow from the place specified in 
+ * this.field_to_sort to the passed parameter.  It will also set 
+ * this.field_to_sort to the new value.  It will also do it in the footers, 
+ * if they exists.
+ * \param field The new field to move it to.
+ */
+nrsTable.prototype.moveSortArrow = function(field)
+{
+       var heading = document.getElementById(this.my_table).tHead.childNodes[0].childNodes[this.field_to_sort];
+       var img = heading.removeChild(heading.getElementsByTagName("IMG")[0]);
+       heading = document.getElementById(this.my_table).tHead.childNodes[0].childNodes[field];
+       heading.appendChild(img);
+       //are there headers in the footers.
+       if(this.foot_headers)
+       {
+               //yes, so switch them too.
+               var footer = document.getElementById(this.my_table).tFoot.childNodes[0].childNodes[this.field_to_sort];
+               var img = footer.removeChild(footer.getElementsByTagName("IMG")[0]);
+               footer = document.getElementById(this.my_table).tFoot.childNodes[0].childNodes[field];
+               footer.appendChild(img);
+       }
+       //finally, set the field to sort by.
+       this.field_to_sort = field;
+}
+
+/**
+ * This function completely destroys a table.  Should be used only when building
+ * a brand new table (ie, new headers).  Else you should use a function like
+ * buildNewData which only deletes the TBody section.
+ */
+nrsTable.prototype.emptyTable = function()
+{
+       var t = document.getElementById(this.my_table);
+       while(t.childNodes.length != 0)
+               t.removeChild(t.childNodes[0]);
+};
+
+/**
+ * This function builds a brand new table from scratch.  This function should
+ * only be called when a brand new table (with headers, footers, etc) needs
+ * to be created.  NOT when refreshing data or changing data.
+ */
+nrsTable.prototype.buildTable = function()
+{
+       //reset the sorting information.
+       this.field_to_sort = 0;
+       this.field_asc = true;
+       
+       //remove the nodes links.
+       delete this.data_nodes;
+       
+       //do we have to calculate the number of pages?
+       if(this.data && this.rows_per_page != -1)
+       {
+               //we do.
+               this.num_pages = Math.ceil(this.data.length / this.rows_per_page);
+               this.current_page = 0;
+       }
+       
+       //blank out the table.
+       this.emptyTable();
+       
+       //this is the table that we will be using.
+       var table = document.getElementById(this.my_table);
+       
+       //is there a caption?
+       if(this.caption)
+       {
+               var caption = document.createElement("CAPTION");
+               caption.setAttribute("align", "top");
+               caption.appendChild(document.createTextNode(this.caption));
+               table.appendChild(caption);
+       }
+       
+       //do the heading first
+       var table_header = document.createElement("THEAD");
+       var table_heading = document.createElement("TR");
+       //since this is a new table the first field is what's being sorted.
+       var curr_cell = document.createElement("TH");
+       var fn = new Function("", "nrsTables['" + this.my_table + "'].fieldSort(" + 0 + ");");
+       if(!this.disable_sorting || this.disable_sorting.indexOf(".0.") == -1)
+               curr_cell.onclick = fn;
+       if(this.header_color)
+               curr_cell.style.backgroundColor = this.header_color;
+       curr_cell.style.cursor = 'pointer';
+       var img = document.createElement("IMG");
+       img.setAttribute("src", this.up_icon);
+       img.setAttribute("border", "0");
+       img.setAttribute("height", "8");
+       img.setAttribute("width", "8");
+       curr_cell.appendChild(document.createTextNode(this.heading[0]));
+       curr_cell.appendChild(img);
+       table_heading.appendChild(curr_cell);
+       //now do the rest of the heading.
+       for(var i = 1; i < this.heading.length; i++)
+       {
+               curr_cell = document.createElement("TH");
+               var fn = new Function("", "nrsTables['" + this.my_table + "'].fieldSort(" + i + ");");
+               if(!this.disable_sorting || this.disable_sorting.indexOf("." + i + ".") == -1)
+                       curr_cell.onclick = fn;
+               if(this.header_color)
+                       curr_cell.style.backgroundColor = this.header_color;
+               curr_cell.style.cursor = 'pointer';
+               //build the sorter
+               curr_cell.appendChild(document.createTextNode(this.heading[i]));
+               table_heading.appendChild(curr_cell);
+       }
+       table_header.appendChild(table_heading);
+       
+       //now the content
+       var table_body = document.createElement("TBODY");
+       this.createDataNodes();
+       if(this.data)
+       {
+               if(this.natural_compare)
+                       this.natSort(0, this.data.length - 1);
+               else
+                       this.quickSort(0, this.data.length - 1);
+               this.recolorRows();
+       }
+
+       //finally, the footer
+       var table_footer = document.createElement("TFOOT");
+       if(this.foot_headers)
+       {
+               table_footer.appendChild(table_heading.cloneNode(true));
+       }
+       
+       if(this.page_nav && this.num_pages > 1)
+       {
+               //print out the page navigation
+               //first and previous page
+               var nav = document.createElement("TR");
+               var nav_cell = document.createElement("TH");
+               nav_cell.colSpan = this.heading.length;
+               
+               var left = document.createElement("DIV");
+               if(document.attachEvent)
+                       left.style.styleFloat = "left";
+               else
+                       left.style.cssFloat = "left";
+               var img = document.createElement("IMG");
+               img.setAttribute("src", this.rew_icon);
+               img.setAttribute("border", "0");
+               img.setAttribute("height", "10");
+               img.setAttribute("width", "10");
+               img.onclick = new Function("", "nrsTables['" + this.my_table + "'].firstPage();");
+               img.style.cursor = 'pointer';
+               left.appendChild(img);
+               //hack to space the arrows, cause IE is absolute crap
+               left.appendChild(document.createTextNode(" "));
+               img = document.createElement("IMG");
+               img.setAttribute("src", this.prev_icon);
+               img.setAttribute("border", "0");
+               img.setAttribute("height", "10");
+               img.setAttribute("width", "10");
+               img.onclick = new Function("", "nrsTables['" + this.my_table + "'].prevPage();");
+               img.style.cursor = 'pointer';
+               left.appendChild(img);
+               //apend it to the cell
+               nav_cell.appendChild(left);
+               
+               //next and last pages
+               var right = document.createElement("DIV");
+               if(document.attachEvent)
+                       right.style.styleFloat = "right";
+               else
+                       right.style.cssFloat = "right";
+               img = document.createElement("IMG");
+               img.setAttribute("src", this.next_icon);
+               img.setAttribute("border", "0");
+               img.setAttribute("height", "10");
+               img.setAttribute("width", "10");
+               img.onclick = new Function("", "nrsTables['" + this.my_table + "'].nextPage();");
+               img.style.cursor = 'pointer';
+               right.appendChild(img);
+               //hack to space the arrows, cause IE is absolute crap
+               right.appendChild(document.createTextNode(" "));
+               img = document.createElement("IMG");
+               img.setAttribute("src", this.fwd_icon);
+               img.setAttribute("border", "0");
+               img.setAttribute("height", "10");
+               img.setAttribute("width", "10");
+               img.onclick = new Function("", "JavaScript:nrsTables['" + this.my_table + "'].lastPage();");
+               img.style.cursor = 'pointer';
+               right.appendChild(img);
+               //apend it to the cell
+               nav_cell.appendChild(right);
+               
+               //page position
+               var pos = document.createElement("SPAN");
+               pos.setAttribute("id", "nav_pos");
+               pos.appendChild(document.createTextNode("Page " + 
+                                               (this.current_page + 1) + " of " + this.num_pages));
+               //append it to the cell.
+               nav_cell.appendChild(pos);
+               
+               nav.appendChild(nav_cell);
+               //append it to the footer
+               table_footer.appendChild(nav);
+       }
+       
+       if(this.footer_color)
+       {
+               for(var i = 0; i < table_footer.childNodes.length; i++)
+                       table_footer.childNodes[i].style.backgroundColor = this.footer_color;
+       }
+       
+       //append the data
+       table.appendChild(table_header);
+       table.appendChild(table_body);
+       table.appendChild(table_footer);
+       if(this.data)
+       {
+               if(this.natural_compare)
+                       this.natSort(0, this.data.length - 1);
+               else
+                       this.quickSort(0, this.data.length - 1);
+       }
+       this.refreshTable();
+};
+
+/**
+ * This function will remove the elements in teh TBody section of the table and
+ * return an array of references of those elements.  This array can then be 
+ * sorted and re-inserted into the table.
+ * \return An array to references of the TBody contents.
+ */
+nrsTable.prototype.extractElements = function()
+{
+       var tbody = document.getElementById(this.my_table).tBodies[0];
+       var nodes = new Array();
+       var i = 0;
+       while(tbody.childNodes.length > 0)
+       {
+               nodes[i] = tbody.removeChild(tbody.childNodes[0]);
+               i++;
+       }
+       return nodes;
+}
+
+/**
+ * This function will re-insert an array of elements into the TBody of a table.
+ * Note that the array elements are stored in the this.data_nodes reference.
+ */
+nrsTable.prototype.insertElements = function()
+{
+       var tbody = document.getElementById(this.my_table).tBodies[0];
+       var start = 0;
+       var num_elements = this.data_nodes.length;
+       if(this.rows_per_page != -1)
+       {
+               start = this.current_page * this.rows_per_page;
+               num_elements = (this.data_nodes.length - start) > this.rows_per_page?
+                                                       this.rows_per_page + start:
+                                                       this.data_nodes.length;
+       }
+       DEBUG("start is " + start + " and num_elements is " + num_elements);
+       for(var i = start; i < num_elements; i++)
+       {
+               tbody.appendChild(this.data_nodes[i]);
+       }
+}
+
+/**
+ * This function will sort the table's data by a specific field.  The field 
+ * parameter referes to which field index should be sorted.
+ * \param field The field index which to sort on.
+ */
+nrsTable.prototype.fieldSort = function(field)
+{
+       if(this.field_to_sort == field)
+       {
+               //only need to reverse the array.
+               if(this.data)
+               {
+                       this.data.reverse();
+                       this.data_nodes.reverse();
+               }
+               //flip the arrow on the heading.
+               this.flipSortArrow();
+       }
+       else
+       {
+               //In this case, we need to sort the array.  We'll sort it last, first 
+               //make sure that the arrow images are set correctly.
+               this.moveSortArrow(field);
+               //finally, set the field to sort by.
+               this.field_to_sort = field;
+               if(this.data)
+               {
+                       //we'll be using our implementation of quicksort
+                       if(this.natural_compare)
+                               this.natSort(0, this.data.length - 1);
+                       else
+                               this.quickSort(0, this.data.length - 1);
+               }
+       }
+       //finally, we refresh the table.
+       this.refreshTable();
+};
+
+/**
+ * This function will refresh the data in the table.  This function should be
+ * used whenever the nodes have changed, or when chanign pages.  Note that 
+ * this will NOT re-sort.
+ */
+nrsTable.prototype.refreshTable = function()
+{
+       this.extractElements();
+       this.recolorRows();
+       this.insertElements();
+       //finally, if there is a nav, upate it.
+       this.updateNav();
+}
+
+/**
+ * This function will advance a page.  If we are already at the last page, then 
+ * it will remain there.
+ */
+nrsTable.prototype.nextPage = function()
+{
+       DEBUG("current page is " + this.current_page + " and num_pages is " + this.num_pages);
+       if(this.current_page + 1 != this.num_pages)
+       {
+               this.current_page++;
+               this.refreshTable();
+       }
+       DEBUG("current page is " + this.current_page + " and num_pages is " + this.num_pages);
+}
+
+/**
+ * This function will go back a page.  If we are already at the first page, then 
+ * it will remain there.
+ */
+nrsTable.prototype.prevPage = function()
+{
+       DEBUG("current page is " + this.current_page + " and num_pages is " + this.num_pages);
+       if(this.current_page != 0)
+       {
+               this.current_page--;
+               this.refreshTable();
+       }
+       DEBUG("current page is " + this.current_page + " and num_pages is " + this.num_pages);
+}
+
+/**
+ * This function will go to the first page.
+ */
+nrsTable.prototype.firstPage = function()
+{
+       if(this.current_page != 0)
+       {
+               this.current_page = 0;
+               this.refreshTable();
+       }
+}
+
+/**
+ * This function will go to the last page.
+ */
+nrsTable.prototype.lastPage = function()
+{
+       DEBUG("lastPage(), current_page: " + this.current_page + " and num_pages: " + this.num_pages);
+       if(this.current_page != (this.num_pages - 1))
+       {
+               this.current_page = this.num_pages - 1;
+               this.refreshTable();
+       }
+}
+
+/**
+ * This function will go to a specific page.  valid values are pages 1 to 
+ * however many number of pages there are.
+ * \param page The page number to go to.
+ */
+nrsTable.prototype.gotoPage = function(page)
+{
+       page--;
+       if(page >=0 && page < this.num_pages)
+       {
+               this.current_page = page;
+               this.refreshTable();
+       }
+}
+
+/**
+ * This function can be used to change the number of entries per row displayed
+ * on the fly.
+ * \param entries The number of entries per page.
+ */
+nrsTable.prototype.changeNumRows = function(entries)
+{
+       if(entries > 0)
+       {
+               this.rows_per_page = entries;
+               //we do.
+               this.num_pages = Math.ceil(this.data.length / this.rows_per_page);
+               this.refreshTable();
+       }
+}
+
+/**
+ * This function will take in a new data array and , optionally, a new cell_link
+ * array OR a new row_link array.  Only one will be used, with the cell_link
+ * array taking precedence.  It will then re-build the table with the new data
+ * array.
+ * \param new_data This is the new data array.  This is required.
+ * \param cell_links This is the new cell links array, a 2D array for each cell.
+ * \param row_links This is the new row links array, a 1D array for each row.
+ */
+nrsTable.prototype.newData = function(new_data, cell_links, row_links)
+{
+       //extract the elements from teh table to clear the table.
+       this.extractElements();
+       //now delete all the data related to this table.  I do this so that 
+       //(hopefully) the memory will be freed.  This is realy needed for IE, whose
+       //memory handling is almost non-existant
+       delete this.data;
+       delete this.data_nodes;
+       delete this.cell_links;
+       delete this.row_links
+       //now re-assign.
+       this.data = new_data;
+       this.cell_links = cell_links;
+       this.row_links = row_links;
+       if(this.rows_per_page != -1)
+       {
+               //we do.
+               this.num_pages = Math.ceil(this.data.length / this.rows_per_page);
+               if(this.num_pages <= 1 && this.page_nav)
+                       this.removeNav();
+               else if(this.page_nav)
+                       this.insertNav();
+               this.current_page = 0;
+       }
+       this.createDataNodes();
+       if(this.field_to_sort != 0)
+               this.moveSortArrow(0);
+       if(!this.field_asc)
+               this.flipSortArrow();
+       this.insertElements();
+       this.updateNav();
+}
+
+/**
+ * This function will remove the NAV bar (if one exists) from the table.
+ */
+nrsTable.prototype.removeNav = function()
+{
+       if(this.page_nav)
+       {
+               //in this case, remove the nav from the existing structure.
+               var table = document.getElementById(this.my_table);
+               var p = 0;
+               if(this.foot_headers)
+                       p++;
+               var nav = table.tFoot.childNodes[p];
+               if(nav)
+               {
+                       table.tFoot.removeChild(nav);
+                       delete nav;
+               }
+       }
+}
+
+/**
+ * This function wil re-insert the nav into the table.
+ */
+nrsTable.prototype.insertNav = function()
+{
+       table = document.getElementById(this.my_table);
+       var p = 0;
+       if(this.foot_headers)
+               p++;
+       if(this.page_nav && !table.tFoot.childNodes[p])
+       {
+               //this means there should be a nav and there isn't one.
+               //print out the page navigation
+               //first and previous page
+               var nav = document.createElement("TR");
+               var nav_cell = document.createElement("TH");
+               nav_cell.colSpan = this.heading.length;
+               
+               var left = document.createElement("DIV");
+               if(document.attachEvent)
+                       left.style.styleFloat = "left";
+               else
+                       left.style.cssFloat = "left";
+               var img = document.createElement("IMG");
+               img.setAttribute("src", this.rew_icon);
+               img.setAttribute("border", "0");
+               img.setAttribute("height", "10");
+               img.setAttribute("width", "10");
+               img.onclick = new Function("", "nrsTables['" + this.my_table + "'].firstPage();");
+               img.style.cursor = 'pointer';
+               left.appendChild(img);
+               //hack to space the arrows, cause IE is absolute crap
+               left.appendChild(document.createTextNode(" "));
+               img = document.createElement("IMG");
+               img.setAttribute("src", this.prev_icon);
+               img.setAttribute("border", "0");
+               img.setAttribute("height", "10");
+               img.setAttribute("width", "10");
+               img.onclick = new Function("", "nrsTables['" + this.my_table + "'].prevPage();");
+               img.style.cursor = 'pointer';
+               left.appendChild(img);
+               //apend it to the cell
+               nav_cell.appendChild(left);
+               
+               //next and last pages
+               var right = document.createElement("DIV");
+               if(document.attachEvent)
+                       right.style.styleFloat = "right";
+               else
+                       right.style.cssFloat = "right";
+               img = document.createElement("IMG");
+               img.setAttribute("src", this.next_icon);
+               img.setAttribute("border", "0");
+               img.setAttribute("height", "10");
+               img.setAttribute("width", "10");
+               img.onclick = new Function("", "nrsTables['" + this.my_table + "'].nextPage();");
+               img.style.cursor = 'pointer';
+               right.appendChild(img);
+               //hack to space the arrows, cause IE is absolute crap
+               right.appendChild(document.createTextNode(" "));
+               img = document.createElement("IMG");
+               img.setAttribute("src", this.fwd_icon);
+               img.setAttribute("border", "0");
+               img.setAttribute("height", "10");
+               img.setAttribute("width", "10");
+               img.onclick = new Function("", "JavaScript:nrsTables['" + this.my_table + "'].lastPage();");
+               img.style.cursor = 'pointer';
+               right.appendChild(img);
+               //apend it to the cell
+               nav_cell.appendChild(right);
+               
+               //page position
+               var pos = document.createElement("SPAN");
+               pos.setAttribute("id", "nav_pos");
+               pos.appendChild(document.createTextNode("Page " + 
+                                               (this.current_page + 1) + " of " + this.num_pages));
+               //append it to the cell.
+               nav_cell.appendChild(pos);
+               
+               nav.appendChild(nav_cell);
+               //append it to the footer
+               table.tFoot.appendChild(nav);
+       }
+}
+
+/**
+ * This function will hide the previous arrow and the rewind arrows from the
+ * nav field.
+ */
+nrsTable.prototype.hideLeftArrows = function()
+{
+       if(!this.page_nav)
+               return;
+       var myTable = document.getElementById(this.my_table);
+       var p = 0;
+       if(this.foot_headers)
+               p++;
+       var nav = myTable.tFoot.childNodes[p];
+       nav.childNodes[0].childNodes[0].style.display = "none";
+}
+
+/**
+ * This function will show the previous arrow and the rewind arrows from the
+ * nav field.
+ */
+nrsTable.prototype.showLeftArrows = function()
+{
+       if(!this.page_nav)
+               return;
+       table = document.getElementById(this.my_table);
+       var p = 0;
+       if(this.foot_headers)
+               p++;
+       var nav = table.tFoot.childNodes[p];
+       nav.childNodes[0].childNodes[0].style.display = "block";
+}
+
+/**
+ * This function will hide the next arrow and the fast foward arrows from the
+ * nav field.
+ */
+nrsTable.prototype.hideRightArrows = function()
+{
+       if(!this.page_nav)
+               return;
+       table = document.getElementById(this.my_table);
+       var p = 0;
+       if(this.foot_headers)
+               p++;
+       var nav = table.tFoot.childNodes[p];
+       nav.childNodes[0].childNodes[1].style.display = "none";
+}
+
+/**
+ * This function will show the next arrow and the fast foward arrows from the
+ * nav field.
+ */
+nrsTable.prototype.showRightArrows = function()
+{
+       if(!this.page_nav)
+               return;
+       table = document.getElementById(this.my_table);
+       var p = 0;
+       if(this.foot_headers)
+               p++;
+       var nav = table.tFoot.childNodes[p];
+       nav.childNodes[0].childNodes[1].style.display = "block";
+}
diff --git a/gui/bweb/html/pix.png b/gui/bweb/html/pix.png
new file mode 100644 (file)
index 0000000..de3da90
Binary files /dev/null and b/gui/bweb/html/pix.png differ
diff --git a/gui/bweb/html/prev.png b/gui/bweb/html/prev.png
new file mode 100644 (file)
index 0000000..c60eb07
Binary files /dev/null and b/gui/bweb/html/prev.png differ
diff --git a/gui/bweb/html/prune.png b/gui/bweb/html/prune.png
new file mode 100644 (file)
index 0000000..96b6d57
Binary files /dev/null and b/gui/bweb/html/prune.png differ
diff --git a/gui/bweb/html/purge.png b/gui/bweb/html/purge.png
new file mode 100644 (file)
index 0000000..9ba7c53
Binary files /dev/null and b/gui/bweb/html/purge.png differ
diff --git a/gui/bweb/html/rcorner.png b/gui/bweb/html/rcorner.png
new file mode 100644 (file)
index 0000000..1099733
Binary files /dev/null and b/gui/bweb/html/rcorner.png differ
diff --git a/gui/bweb/html/remove.png b/gui/bweb/html/remove.png
new file mode 100644 (file)
index 0000000..19eaef3
Binary files /dev/null and b/gui/bweb/html/remove.png differ
diff --git a/gui/bweb/html/right.gif b/gui/bweb/html/right.gif
new file mode 100755 (executable)
index 0000000..9ab5a5f
Binary files /dev/null and b/gui/bweb/html/right.gif differ
diff --git a/gui/bweb/html/right.png b/gui/bweb/html/right.png
new file mode 100644 (file)
index 0000000..ac0c51a
Binary files /dev/null and b/gui/bweb/html/right.png differ
diff --git a/gui/bweb/html/save.png b/gui/bweb/html/save.png
new file mode 100644 (file)
index 0000000..b52d1d7
Binary files /dev/null and b/gui/bweb/html/save.png differ
diff --git a/gui/bweb/html/style.css b/gui/bweb/html/style.css
new file mode 100644 (file)
index 0000000..2831248
--- /dev/null
@@ -0,0 +1,720 @@
+* {
+    font-family: Verdana, Arial, Helvetica, sans-serif, monospace;
+}
+
+body {  
+    background: #606060;
+    color: #000000;  
+}  
+
+a:link {    
+    color: #0000FF;    
+    background: transparent;
+    text-decoration: none;
+}    
+    
+a:visited {    
+    color: #990099;    
+    background: transparent;
+    text-decoration: none;
+}    
+    
+a:active {    
+    color: #000000;    
+    background: #ADD8E6;
+    text-decoration: none;
+}    
+    
+h1.rubrique_info {  
+    color: #990033;  
+    margin: 0px 0px 0px 0px;
+    padding: 0em; 
+    border: 0px;
+    font-size: 12px;
+}
+h1.connexe {
+    font-size: 12px;
+    padding: 0em;
+    margin: 0px 0px 0px 0px;
+    color: #990033;
+}
+
+a.rubrique_infolink {
+    text-decoration: none;
+}
+ul.rubrique_infoul {
+    display: inline;
+    list-style-type: square;
+}
+ul.rubrique_infoul * {
+    width: 100%;
+}
+li.rubrique_infoul {
+    margin-left: 15px;
+}
+h1 {
+    color: #990033;   
+}
+
+div.main {  
+    background: white;  
+    color: #000000;  
+    margin-left: 5px;
+    margin-right: 5px;
+    /*padding-left: 10px;
+    padding-right: 10px;*/
+    border: 1px black solid;
+    text-align: left;
+    font-size: 12px;
+}
+div.lsfnbanner {
+       margin-left: 150px;
+       margin-right: 170px;
+       border-top: none;
+    padding-left: 10px;
+    padding-right: 10px;
+    border-bottom: 1px black solid;
+    border-right: 1px black solid;
+    border-left: 1px black solid;
+    text-align: left;
+    font-size: 11px;
+       padding-top: 2px;
+       background-color: #eeeae6;
+}
+div.footer {
+    padding-top: 5px;
+    padding-bottom: 3px;
+    border-top: 1px black solid;
+       border-left: 1px black solid;
+       border-right: 1px black solid;
+    text-align: left;
+    font-size: 9px;
+    background: #dcdff4;
+       margin-top: 40px;
+       margin-left: 20px;
+       margin-right: 20px;
+}
+div.footer p {
+       margin-left: 10px;
+       margin-top: 2px;
+       margin-bottom: 2px;
+}
+a.lsfnlink:link,a.lsfnlink:visited,a.lsfnlink:active {
+    text-decoration: none;
+    color: #333333;
+    font-size: 10px;
+}
+a.lsfnlink:hover {
+    text-decoration: underline;
+    color: black;
+}
+div.menubartop {
+    margin-bottom: 10px;
+    padding-left: 10px;
+    padding-right: 10px;
+    padding-top: 0px;
+    font-size: 13px;
+}
+div.smallmenubar {
+    background: white;
+    padding-left: 10px;
+    padding-right: 10px;
+    padding-top: 0px;
+    padding-bottom: 0px;
+    font-weight:bold;
+    font-size: 10px;
+    text-align: right;
+}
+div.menuevent {
+    float: left;
+    width: 350px;
+    font-size: 11px;
+    text-align: left;
+    padding-top: 0px;
+    padding-bottom: 0px;
+    padding-left: 10px;
+    font-weight: bold;
+    margin: 0px;
+}
+div.menubar {
+    background: #cac2a8;
+    border-top: 1px black solid;
+    border-bottom: 1px black solid;
+    padding-left: 10px;
+    padding-right: 10px;
+    padding-top: 3px;
+       padding-bottom: 2px;
+    font-weight:bold;
+    font-size: 13px;
+}
+div.menubar a {
+       text-decoration: none;
+}
+div.menubar p {
+       padding: 0px;
+       margin: 0px;
+}
+div.menudate {
+    float: left;
+    width: 130px;
+       padding-top: 5px;
+}
+div.menuaccroche {
+       margin-left: 30px;
+       float: left;
+    text-decoration: underline;
+       font-size: 14px;
+}
+div.menusearch {
+       float: right;
+    text-align: right;
+       padding-top: 5px;
+       width: 170px;
+}
+div.menusearch p {
+       margin: 0px 0px 0px 0px;
+}
+div.newsletter {
+       float: right;
+       text-align: right;
+       margin: 0px;
+       padding: 0px;
+       font-size: 8px;
+       font-weight: normal;
+}
+div.newsletter p {
+       margin: 0px 0px 0px 0px;
+}
+.searchinput {
+    border: solid 1px black;
+}
+.newsletterinput {
+    border: solid 1px black;
+    font-weight: normal;
+}
+a#menulinkselect {
+       color: #ed7e00;
+}
+
+div.leftbox {
+    width: 200px; 
+    float: left; 
+    padding-left: 5px;
+    padding-right: 5px;
+    padding-bottom: 5px;
+    border-right: 1px black solid;
+    border-bottom: 1px black solid;
+    background: white;
+    margin-bottom: 10px;
+    margin-right: 20px;
+    overflow: hidden;
+}
+div.leftbox h1 {
+       text-transform: uppercase;
+       font-weight: bold;
+       color: #ed7e00;
+       font-size: 10px;
+       margin: 0px;
+}
+div.leftbox h2 {
+       font-weight: bold;
+       font-size: 12px;
+       margin: 0px;
+}
+div.leftbox ul {
+    list-style-type: square;
+       margin-bottom: 10px;
+       margin-left: 0em;
+       padding-left: 0em;
+}
+div.leftbox li {
+       margin-left: 10px;
+       margin-top: 10px;
+}
+
+div.rightbox {
+    width: 150px; 
+    float: right; 
+    padding-top: 10px;
+    padding-left: 5px;
+       padding-right: 15px;
+    padding-bottom: 5px;
+    border-left: 1px black solid;
+    border-bottom: 1px black solid;
+       text-align: left;
+}
+div.tipdiv {
+       margin-right: 50px;
+       padding-top: 5px;
+       padding-right: 10px;
+       padding-left: 10px;
+       text-align: justify;
+       background-color: #eee;
+       border: black solid 1px;
+       margin-left: 10px;
+}
+div.tipdiv h1 {
+       font-weight: bold;
+       font-size: 14px;
+       color: black;
+    margin-top: 0px;
+    margin-bottom: 20px;
+}
+div.tipdiv h2 {
+       text-transform: uppercase;
+       font-weight: bold;
+       color: #ed7e00;
+       font-size: 12px;
+       margin: 0px;
+}
+
+div.newsdiv {
+    margin-left: 220px;
+    margin-right: 180px;
+    margin-top: 10px;
+    margin-bottom: 20px;
+       text-align: justify;
+}
+div.newsdiv h1 {
+       font-weight: bold;
+       font-size: 14px;
+       margin: 0px;
+}
+div.newsdiv h2 {
+       font-weight: normal;
+       font-size: 12px;
+       margin: 0px;
+}
+div.newsdiv h3 {
+       font-weight: normal;
+       font-size: 12px;
+       margin-bottom: 20px;
+}
+div.objdiv {
+    margin-left: 220px;
+    margin-right: 20px;
+    margin-top: 10px;
+    margin-bottom: 20px;
+}
+
+h1.newstitle {
+    text-align: left;
+    font-size: 14px;
+    margin: 0px 0px 0px 0px;
+    color: black;
+}
+div.titlediv {
+    border-top: solid #cac2a8 2px;
+    margin-top: 20px;
+    background-color: #eeeae6;
+    padding-left: 10px;
+    font-size: 11px;
+}
+div.bodydiv {
+    border: solid #9e9784 1px;
+    padding-left: 10px;
+    padding-right: 10px;
+       padding-top: 10px;
+       padding-bottom: 5px;
+    margin-top: 2px;
+    text-align: justify;
+}
+div.bodydiv ul {
+    list-style-type: square;
+}
+
+div.comments {
+    padding: 10px;
+    border-top: solid 2px #d37537;
+    border-bottom: solid 2px #d37537;
+    margin-top: 20px;
+    margin-bottom: 10px;
+    background-color: #cacaca;
+    font-size: 12px;
+    line-height: 1.3em;
+}
+
+.comment-vote {
+    font-style: italic;
+}
+
+p.commentsbody {
+    border-left-style: solid;
+    border-width: 1px;
+    border-color: rgb(0, 0, 0);
+    padding-left: 10px;
+       text-align: justify;
+       margin-right: 20px;
+}
+div.commentsreply {
+       /*margin-left: 220px;*/
+       text-align: center;
+       margin-top: 50px;
+}
+
+ul.commentsul {
+    list-style-type: none;
+       margin-bottom: 10px;
+       margin-left: 1.25em;
+       padding-left: 0em;
+       /*border-left: 1px solid black;*/
+}
+ul.commentsli {
+       margin: 10px;
+}
+div.comments li {
+       margin-top: 20px;
+       margin-left: 2px;
+}
+
+div.comments h1 {
+    font-size: 12px;
+    color: black;
+    margin: 0px 20px 3px 0px;
+    background-color: rgb(226, 226, 226);
+    padding-left: 1px;
+    font-weight: normal;
+}
+
+div.articlediv {
+    padding-left: 20px;
+    padding-right: 20px;
+    padding-top: 10px;
+    padding-bottom: 20px;
+    margin-right: 180px;
+    margin-left: 220px;
+    border: solid 1px black;
+    margin-top: 10px;
+    text-align: justify;
+    background-color: #E2E2E2;
+}
+img {
+    border: 0px;
+}
+div.sectionimg {
+    float: left;
+    margin-right: 10px;
+    margin-top: 5px;
+}
+p.hautpage {
+       margin-top: 20px;
+       margin-bottom: 20px;
+       margin-left: 10px;
+}
+div.leftcol {
+       /*width: 202px;*/ 
+       width: 202px;
+       float: left;
+       padding: 0px;
+    /*overflow: hidden;*/
+}
+div.logodiv {
+       border-right: 1px black solid;
+       border-bottom: 1px black solid;
+       padding: 0px;
+       line-height: 0px
+}
+div.loginbox {
+       margin-left: 4px;
+       border: solid #a59f8b 1px;
+       margin-top: 2px;
+       padding: 5px;
+       background-color: #fff2e8;
+       font-size: 10px;
+}
+div.loginbox p {
+       margin: 0px;
+       padding: 0px;
+}
+div.loginbox ul {
+       margin-left: 10px;
+       margin-top: 0px;
+       margin-bottom: 0px;
+       padding: 0px;
+       list-style-type: none;
+}
+div.loginbox h1 {
+       text-transform: uppercase;
+       font-weight: bold;
+       color: #ed7e00;
+       font-size: 10px;
+       margin: 0px;
+}
+div.loginbox h2 {
+       font-weight: bold;
+       font-size: 12px;
+       margin: 0px;
+}
+div.loginbox h3 {
+       margin-top: 0px;
+       margin-bottom: 5px;
+       font-size: 12px;
+}
+div.polldivtitle {
+       margin-bottom: 1px;
+       background-color: #cac2a8;
+       margin-left: 4px;
+       margin-top: 15px;
+       padding-left: 5px;
+       font-size: 10px;
+       border-top: solid #a59f8b 1px;
+       border-bottom: solid #a59f8b 1px;
+       text-transform: uppercase;
+}
+div.polldiv {
+       margin-left: 4px;
+       border: 1px #a59f8b solid;
+       margin-top: 0px;
+       padding: 5px;
+       background: #fff2e8;
+}
+div.polldiv p {
+margin: 5px; padding: 0px;
+}
+div.polldiv ul {
+       margin-left: 5px;
+       margin-top: 0px;
+       margin-bottom: 10px;
+       padding: 0px;
+    list-style-type: none;
+}
+div.otherboxtitle {
+       margin-bottom: 2px;
+       background-color: #e3dabc;
+       margin-left: 4px;
+       margin-top: 10px;
+       padding-left: 5px;
+       padding-top: 2px;
+       font-size: 11px;
+       border-top: solid #777364 1px;
+       border-bottom: solid #777364 1px;
+       /*text-transform: uppercase;*/
+       /*font-weight: bold;*/
+}
+div.otherbox {
+       margin-left: 4px;
+       margin-right: 1px;
+       border: 1px #a59f8b solid;
+       margin-top: 0px;
+       padding: 5px;
+       text-align: justify;
+       background: #fff2e8;
+       font-size: 10px;
+}
+div.otherbox h1 {
+       text-transform: uppercase;
+       font-weight: bold;
+       color: #ed7e00;
+       font-size: 10px;
+       margin: 0px;
+}
+div.otherbox h2 {
+       font-weight: bold;
+       font-size: 11px;
+       margin: 0px;
+}
+div.otherbox p {
+       margin-top: 5px;
+       margin-bottom: 10px;
+}
+div.rightlogo { 
+    width: 90px; 
+    float: right;
+    margin-right: 0px;
+    padding-top: 0px;
+    padding-left: 0px;
+    padding-bottom: 0px;
+}   
+div.centraldiv {
+    margin-left: 220px;
+    margin-right: 10px;
+    margin-bottom: 20px;
+       margin-top: 10px;
+}
+div.centraldiv h1 {
+       font-weight: bold;
+       font-size: 14px;
+       margin: 0px;
+}
+div.centraldiv h2 {
+       font-weight: normal;
+       font-size: 12px;
+       margin: 0px;
+}
+div.centraldiv h3 {
+       font-weight: normal;
+       font-size: 12px;
+       margin-bottom: 20px;
+}
+div.centralinfo {
+       margin-bottom: 20px;
+}
+div.lefttopbox {
+       padding-left: 5px;
+       padding-right: 5px;
+       padding-top: 5px;
+       text-align: justify;
+       border: 2px #a59f8b solid;
+       background: #ffffbb;
+       /*
+       background: #c8ff9b;
+       */
+       font-size: 13px;
+       width: 60%;
+       float: left;
+}
+div.lefttopbox p {
+       margin-top: 5px; margin-bottom: 10px;
+}
+div.lefttopbox h1 {
+       font-size: 13px;
+       font-weight: bold;
+       margin: 0px;
+       text-align: right;
+}
+div.lefttopbox h2 {
+       text-transform: uppercase;
+       font-weight: bold;
+       color: #ed7e00;
+       font-size: 13px;
+       margin: 0px;
+}
+div.lefttopbox h3 {
+       font-weight: bold;
+       font-size: 14px;
+       margin: 0px;
+}
+div.righttopbox {
+       border: 1px #a59f8b solid;
+       background: white;
+       padding: 5px;
+       text-align: justify;
+       font-size: 12px;
+       width: 34%;
+       float: right;
+}
+div.righttopbox h1 {
+       text-transform: uppercase;
+       font-weight: bold;
+       color: #ed7e00;
+       font-size: 10px;
+       margin: 0px;
+}
+div.righttopbox h2 {
+       font-weight: bold;
+       font-size: 12px;
+       margin: 0px;
+}
+div.boardindex {
+       text-align: justify;
+       font-size: 11px;
+       padding: 10px;
+       margin-left: 20px;
+       margin-right: 20px;
+}
+a.boardindex:link,a.boardindex:visited,a.boardindex:active {
+       text-decoration:none;
+       color: red;
+}
+div.boardleftmsg {
+       float: left;
+       margin-top: 3px;
+}
+div.boardrightmsg {
+       margin-left: 130px;
+       margin-top: 3px;
+       padding-left: 5px;
+}
+div.journalbody {
+       margin-left: 40px;
+       margin-top: 40px;
+}
+div.journalbody h1 {
+       font-size: 15px;
+       font-weight: bold;
+}
+div.journalbody p {
+       margin-bottom: 20px;
+}
+.formulaire {
+       border: solid 1px black;
+       font-size: 12px;
+       background-color: #fffbf7;
+       color: #000000;
+}
+.formulaire:focus {
+       background-color: #eeeae6;
+       border: 1px solid #777;
+       color: #000000;
+}
+.newcomments {
+       color: red;
+       font-weight: bold;
+}
+.misspelled {
+       color: red;
+       font-weight: bold;
+}
+div.commentsreplythanks {
+       margin-left: 100px;
+       margin-top: 50px;
+       margin-right: 100px;
+       background-color: #eee;
+       border: black solid 1px;
+       padding: 10px;
+}
+div.archivediv {
+       margin-right: 20px;
+}
+.archivedate {
+       color:#f30;
+}
+.archivelink {
+       font-size: 14px;
+       font-weight: bold;
+       text-decoration: underline;
+}
+div.forumgroup {
+       text-align: left;
+       border: solid black 1px;
+       padding: 10px 20px 20px 10px;
+       background-color: #eee;
+}
+
+div.adminall {
+       font-size: 12px;
+       padding: 10px;
+}
+div.floatwin {
+    position:absolute;
+    top: 150px;
+    left: 450px;
+    width:200px;
+    visibility:hidden;
+    background: #dcdff4;
+    padding: 5px;
+    border: solid black 1px;
+}
+
+div.poll-result-bar {
+       background-color: #bbb;
+       color: black;
+       border: solid 1px black;
+}
+div.funbanner {
+       text-align: right;
+       border-top: #aaa solid 1px;
+       border-bottom: #aaa solid 1px;
+       padding-right: 20px;
+       padding-top: 2px;
+       padding-bottom: 2px;
+       font-size: 10px;
+       background-color: #fff2e8;
+       font-weight: bold;
+       margin-top: 10px;
+}
+
+div.replie
+{
+       display: none;  
+}
diff --git a/gui/bweb/html/tape.png b/gui/bweb/html/tape.png
new file mode 100644 (file)
index 0000000..6571513
Binary files /dev/null and b/gui/bweb/html/tape.png differ
diff --git a/gui/bweb/html/unload.png b/gui/bweb/html/unload.png
new file mode 100644 (file)
index 0000000..ce290ba
Binary files /dev/null and b/gui/bweb/html/unload.png differ
diff --git a/gui/bweb/html/up.gif b/gui/bweb/html/up.gif
new file mode 100755 (executable)
index 0000000..4824985
Binary files /dev/null and b/gui/bweb/html/up.gif differ
diff --git a/gui/bweb/html/update.png b/gui/bweb/html/update.png
new file mode 100644 (file)
index 0000000..c7e691b
Binary files /dev/null and b/gui/bweb/html/update.png differ
diff --git a/gui/bweb/html/zoom.png b/gui/bweb/html/zoom.png
new file mode 100644 (file)
index 0000000..1ac4864
Binary files /dev/null and b/gui/bweb/html/zoom.png differ
diff --git a/gui/bweb/install_bweb b/gui/bweb/install_bweb
new file mode 100755 (executable)
index 0000000..501f9b7
--- /dev/null
@@ -0,0 +1,126 @@
+#!/bin/sh
+#
+# Change the following four environment variables to suit your system
+#   Note, the configuration below works on a stock SuSE 10.2 system
+#
+# You can, in general, execute this file multiple times.  However, if
+#   you edit certain of the installed files, your changes might be lost.
+#   This script will not overwrite any installed /etc/bacula/bweb.conf
+#
+# Configuration directory for bweb
+CONF_DIR=/etc/bacula
+#
+# Root directory of web files       
+#
+WEB_DIR=/srv/www/htdocs 
+#
+# share directory for programs
+#
+SHARE_DIR=/usr/share
+#
+# cgi_bin location for web server
+#
+CGI_BIN=/srv/www/cgi-bin
+#
+# Userid the web server is running under
+#
+HTTP_USER=wwwrun
+HTTP_GROUP=www
+
+# Bacula database name and password
+DB=bacula
+DB_PW=""
+EMAIL_ADDR="xxx@localhost"
+MTX="/sbin/mtx"
+
+if [ `whoami` != "root" ] ; then
+  echo "You must be root to run this script."
+  exit 1
+fi
+
+#
+# Normally you should not need to change the following
+#
+# first, copy the bweb perl library into your PERL5 INC path
+sed -i "s!/etc/bacula!${CONF_DIR!" lib/Bweb.conf
+perl Makefile.PL
+make install
+
+# copy the bweb perl program to your cgi location
+if [ ! -d ${CGI_BIN}/bweb ] ; then
+   mkdir -m 755 ${CGI_BIN}/bweb
+fi
+install -m 755 -o root -g root  cgi/*.pl ${CGI_BIN}/bweb
+
+# get a config file
+if [ ! -d ${CONF_DIR} ] ; then
+   mkdir -m 755 ${CONF_DIR}
+   chown root:bacula ${CONF_DIR}
+fi
+
+# Setup a default ${CONF_DIR}/bweb.conf
+if [ ! -e ${CONF_DIR}/bweb.conf ] ; then
+cat > ${CONF_DIR}/bweb.conf <<END_OF_DATA
+\$VAR1 = bless( {
+  'graph_font' => '/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf',
+  'name' => undef,
+  'config_file' => '${CONF_DIR}/bweb.conf',
+  'bconsole' => '/usr/sbin/bconsole -n -c /etc/bacula/bconsole.conf',
+  'ach_list' => {
+     'S1_L80' => bless( {
+         'info' => {
+                     'drive' => 0,
+                     'io' => 0,
+                     'slot' => 0
+                   },
+         'name' => 'S1_L80',
+         'bweb' => undef,
+         'device' => '/dev/changer',
+         'drive' => [],
+         'debug' => 0,
+         'label' => {},
+         'precmd' => 'sudo',
+         'io' => [],
+         'mtxcmd' => '${MTX}',
+         'drive_name' => [
+                           'S1_L80_SDLT0',
+                           'S1_L80_SDLT1'
+                         ],
+         'slot' => []
+       }, 'Bweb::Autochanger' )
+   },
+  'password' => '${DB_PW}',
+  'template_dir' => '${SHARE_DIR}/bweb/tpl',
+  'dbi' => 'DBI:mysql:database=bacula',
+  'error' => '',
+  'debug' => 0,
+  'user' => '${DB}',
+  'email_media' => '${EMAIL_ADDR}'
+}, 'Bweb::Config' );
+END_OF_DATA
+fi
+
+chown ${HTTP_USER} ${CONF_DIR}/bweb.conf
+
+# copy the bweb template file
+if [ ! -d ${SHARE_DIR}/bweb/tpl ] ; then
+   mkdir -p ${SHARE_DIR}/bweb/tpl
+fi
+install -m 644 -o root -g root  tpl/*.tpl ${SHARE_DIR}/bweb/tpl
+
+# copy the bweb graphics elements (bweb elements must reside in /bweb)
+if [ ! -d ${WEB_DIR} ] ; then
+   mkdir ${WEB_DIR}/bweb
+fi
+install -m 644 -o root -g root  html/*.{js,png,css,gif,ico,html} ${WEB_DIR}/bweb
+
+echo " "
+echo "Please edit /etc/bweb.conf and ensure that all the paths to"
+echo "  the various programs and files such as bconsole, bconsole.conf"
+echo "  are correct, and that the DBI driver is correct (default mysql)"
+echo "  and has the right password for your DB"
+echo " "
+
+
+# done !
diff --git a/gui/bweb/lang/es/tpl/about.tpl b/gui/bweb/lang/es/tpl/about.tpl
new file mode 100644 (file)
index 0000000..01d944b
--- /dev/null
@@ -0,0 +1,39 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Acerca </h1>
+</div>
+<div class='bodydiv'>
+<pre>
+   Bweb - A Bacula web interface
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+
+   The main author of Bweb is Eric Bollengier.
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation plus additions
+   that are listed in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
+   Switzerland, email:ftf@fsfeurope.org.
+
+   nrsTable Copyright 2005 New Roads School (GPL)
+   kaiska css Copyright Willy Morin (BWL)
+</pre>
+</div>
diff --git a/gui/bweb/lang/es/tpl/ach_add.tpl b/gui/bweb/lang/es/tpl/ach_add.tpl
new file mode 100644 (file)
index 0000000..ddf03a2
--- /dev/null
@@ -0,0 +1,72 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'><TMPL_UNLESS name>Nueva</TMPL_UNLESS> Autochanger </h1>
+</div>
+<div class='bodydiv'>
+   Tiene que crear una Ubicación, la cual deberá tener el mismo nombre.<br/><br/>
+
+   <form name='form1' action="?" method='get'>
+    <table>
+     <tr><td>Nombre :</td>     
+         <td>
+          <select name='ach' class='formulaire' id='ach'>
+<TMPL_LOOP devices><option value='<TMPL_VAR name>'><TMPL_VAR name></option></TMPL_LOOP>
+          </select>
+         </td>
+     </tr>
+     <tr><td>Pre-comando :</td> 
+         <td> <input class="formulaire" type='text' id='precmd' value='sudo'
+           title='can be "sudo" or "ssh storage@storagehost"...' name='precmd'>
+         </td>
+     </tr>
+     <tr><td>Comando mtx :</td> 
+         <td> <input class="formulaire" type='text' name='mtxcmd' size='32'
+               value='/usr/sbin/mtx' id='mtxcmd'>
+         </td>
+     </tr>
+     <tr><td>Device :</td> 
+         <td> <input class="formulaire" type='text' name='device' 
+               value='/dev/changer' id='device'>
+         </td>
+     </tr>
+    <tr><td><b>Drives</b></td><td/></tr>
+    <TMPL_LOOP devices>
+    <tr>
+     <td><input class='formulaire' type='checkbox' id='drive_<TMPL_VAR name>'
+                name='drives' value='<TMPL_VAR name>'><TMPL_VAR name>
+     </td>
+     <td>index <input type='text' title='drive index' class='formulaire'
+               id='index_<TMPL_VAR name>' value='' 
+                name='index_<TMPL_VAR name>' size='3'>
+     </td>
+    </tr>
+    </TMPL_LOOP>
+    </table>
+    <input type="image" name='action' value='ach_add' src='/bweb/save.png'>
+   </form>
+</div>
+
+<script type="text/javascript" language="JavaScript">
+  <TMPL_IF name>
+  for (var i=0; i < document.form1.ach.length; ++i) {
+     if (document.form1.ach[i].value == '<TMPL_VAR name>') {
+        document.form1.ach[i].selected = true;
+     }
+  }
+  </TMPL_IF>
+  <TMPL_IF mtxcmd>
+     document.getElementById('mtxcmd').value='<TMPL_VAR mtxcmd>';
+  </TMPL_IF>
+  <TMPL_IF precmd>
+     document.getElementById('precmd').value='<TMPL_VAR precmd>';
+  </TMPL_IF>
+  <TMPL_IF device>
+     document.getElementById('device').value='<TMPL_VAR device>';
+  </TMPL_IF>
+  <TMPL_IF drives>
+   <TMPL_LOOP drives>
+     document.getElementById('drive_<TMPL_VAR name>').checked=true;
+     document.getElementById('index_<TMPL_VAR name>').value=<TMPL_VAR index>;
+   </TMPL_LOOP>
+  </TMPL_IF>
+</script>
diff --git a/gui/bweb/lang/es/tpl/ach_content.tpl b/gui/bweb/lang/es/tpl/ach_content.tpl
new file mode 100644 (file)
index 0000000..63e61f5
--- /dev/null
@@ -0,0 +1,161 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> 
+Autochanger : <TMPL_VAR Name> (<TMPL_VAR nb_drive> Drives
+<TMPL_IF nb_io><TMPL_VAR nb_io> IMPORT/EXPORT</TMPL_IF>)</h1>
+ </div>
+ <div class='bodydiv'>
+   <form action='?' method='get'>
+    <input type='hidden' name='ach' value='<TMPL_VAR name>'>
+    <TMPL_IF "Update">
+    <font color='red'> Debe ejecutar el comando update slot, El estado del Autochanger es diferente al de las slots de bacula </font>
+    <br/>
+    </TMPL_IF>
+    <table border='0'>
+    <tr>
+    <td valign='top'>
+    <div class='otherboxtitle'>
+     Tools
+    </div>
+    <div class='otherbox'>
+<label>
+<input type="image" name='action' value='label_barcodes'
+        title='run label barcodes' src='/bweb/label.png'>Label
+</label>
+<TMPL_IF nb_io>
+<label>
+<input type="image" name='action' value='eject'
+        title='put selected media on i/o' src='/bweb/extern.png'>
+Exportar
+</label>
+<label>
+<input type="image" name='action' value='clear_io'
+        title='Clear i/o' src='/bweb/intern.png'>
+Limpiar I/O
+</label>
+</TMPL_IF>
+<label>
+<input type="image" name='action' value='update_slots'
+        title='run update slots' src='/bweb/update.png'>
+Actualizar
+</label>
+<br/><br/>
+<label>
+<input type="image" name='action' value='ach_load'
+       title='mount drive' src='/bweb/load.png'>
+Montar
+</label>
+<label>
+<input type="image" name='action' value='ach_unload'
+       title='umount drive' src='/bweb/unload.png'>
+Desmontar
+</label>
+
+   </div>
+    <td width='200'/>
+    <td>
+    <b> Drives: </b><br/>
+    <table id='id_drive'></table> <br/>
+    </td>
+    </tr>
+    </table>
+    <b> Contenido: </b><br/>
+    <table id='id_ach'></table>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Slot Real", "Slot", "Nombre Volumen","Bytes Vol","Estado Vol",
+                      "Tipo Medio","Nombre Pool","Fecha Escritura", 
+                       "Expiración", "Selección");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP Slots>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.name = 'slot';
+chkbox.value = '<TMPL_VAR realslot>';
+
+data.push( new Array(
+"<TMPL_VAR realslot>",
+"<TMPL_VAR slot>",
+"<TMPL_VAR volumename>",
+human_size(<TMPL_VAR volbytes>),
+"<TMPL_VAR volstatus>",
+"<TMPL_VAR mediatype>",
+"<TMPL_VAR name>",
+"<TMPL_VAR lastwritten>",
+"<TMPL_VAR expire>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id_ach",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+// page_nav: true,
+// rows_per_page: rows_per_page,
+// disable_sorting: new Array(5,6)
+ padding: 3
+}
+);
+
+var header = new Array("Index", "Nombre Drive", "Nombre Volumen", "Selección");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP Drives>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.name = 'drive';
+chkbox.value = '<TMPL_VAR index>';
+
+data.push( new Array(
+"<TMPL_VAR index>",
+"<TMPL_VAR name>",
+"<TMPL_VAR load>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id_drive",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+// page_nav: true,
+// rows_per_page: rows_per_page,
+// disable_sorting: new Array(5,6),
+ padding: 3
+}
+);
+
+</script>
diff --git a/gui/bweb/lang/es/tpl/begin.tpl b/gui/bweb/lang/es/tpl/begin.tpl
new file mode 100644 (file)
index 0000000..2c63817
--- /dev/null
@@ -0,0 +1,66 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+<head>
+<title>Bweb - Bacula Web Interface</title>
+<link rel="SHORTCUT ICON" href="/bweb/favicon.ico">
+<script type="text/javascript" language="JavaScript" src="/bweb/natcompare.js"></script>
+<script type="text/javascript" language="JavaScript" src="/bweb/nrs_table.js"></script>
+<script type="text/javascript" language="JavaScript" src="/bweb/bweb.js"></script>
+<link type="text/css" rel="stylesheet" href="/bweb/style.css"/>
+<link type="text/css" rel="stylesheet" href="/bweb/kaiska.css"/>
+<link type="text/css" rel="stylesheet" href="/bweb/bweb.css"/>
+</head>
+<body>
+
+<script type="text/javascript" language="JavaScript">
+if (navigator.appName == 'Konqueror') {
+        alert("Sorry at this moment, bweb works only with mozilla.");
+}
+</script>
+
+<ul id="menu">
+ <li><a href="bweb.pl?">Principal</a> </li>
+ <li><a href="bweb.pl?action=client">Clientes</a></li>
+ <li><a href="bweb.pl?action=run_job">Jobs</a>
+   <ul> 
+     <li><a href="bweb.pl?action=run_job">Jobs Definidos</a>
+     <li><a href="bweb.pl?action=job">Últimos Jobs</a> </li>
+     <li><a href="bweb.pl?action=running">Jobs en Ejecución</a>
+     <li><a href="bweb.pl?action=next_job">Próximos Jobs</a> </li>
+     <li><a href="bweb.pl?action=restore" title="Launch brestore">Recuperación</a> </li>
+   </ul>
+ </li>
+ <li style="padding: 0.25em 2em;">Medios
+  <ul>
+     <li><a href="bweb.pl?action=pool">Pools</a> </li>
+     <li><a href="bweb.pl?action=location">Ubicaciones</a> </li>
+     <li><a href="bweb.pl?action=media">Todos los Medios</a><hr></li>
+     <li><a href="bweb.pl?action=extern_media">Expulsar Medio</a> </li>
+     <li><a href="bweb.pl?action=intern_media">Cargar Medio</a> </li>
+  </ul>
+ </li>
+<TMPL_IF achs>
+ <li style="padding: 0.25em 2em;">Libreria
+  <ul>
+<TMPL_LOOP achs>
+   <li><a href="bweb.pl?action=ach_view;ach=<TMPL_VAR name>"><TMPL_VAR name></a></li>
+</TMPL_LOOP>
+  </ul>
+ </li>
+</TMPL_IF> 
+ <li><a href="bweb.pl?action=graph"> Estadísticas </a></li>
+ <li> <a href="bweb.pl?action=view_conf"> Configuración </a> </li>
+ <li> <a href="bweb.pl?action=about"> Acerca </a> </li>
+ <li style="padding: 0.25em 2em;float: right;">&nbsp;Usuario  <TMPL_VAR NAME=loginname> </li>
+ <li style="float: right;white-space: nowrap;">
+<input type="image" class="button" title="buscar medio" onclick="search_media();" src="/bweb/tape.png"><input type="image" title="buscar cliente" onclick="search_client();" src="/bweb/client.png">&nbsp;<input class='formulaire' style="margin: 0 2px 0 2px; padding: 0 0 0 0;" id='searchbox' type='text' size='8' value="buscar..." onclick="this.value='';" title="buscar por medio o cliente"></li>
+</ul>
+
+<form name="search" action="bweb.pl?" method='GET'>
+ <input type="hidden" name="action" value="">
+ <input type="hidden" name="re_media" value="">
+ <input type="hidden" name="re_client" value="">
+</form>
+
+<div style="clear: left;">
+<div style="float: left;">
diff --git a/gui/bweb/lang/es/tpl/change_location.tpl b/gui/bweb/lang/es/tpl/change_location.tpl
new file mode 100644 (file)
index 0000000..496c61a
--- /dev/null
@@ -0,0 +1,37 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> 
+   Mover medio
+  </h1>
+ </div>
+ <div class='bodydiv'>
+
+<form action="?" method='GET'>
+<table>
+<tr>
+<td><b>Para: </b></td><td><input class='formulaire' name='email' value='<TMPL_VAR email>'></td>
+</tr><tr>
+<td><b>Asunto: </b></td><td><input class='formulaire' name='subject' value='[BACULA] Mover medio a <TMPL_VAR newlocation>' size='80'></td>
+</tr><tr>
+<td></td>
+<td>
+<textarea name='content' class='formulaire' cols='80' rows='32'>
+Estimado,
+
+Puede mover este medio a <TMPL_VAR newlocation>
+Medio :
+<TMPL_LOOP Medias>
+ - <TMPL_VAR VolumeName>  (<TMPL_VAR location>)
+</TMPL_LOOP>
+
+Cuando finalice, puede actualizar la ubicacion del medio ? 
+(puede usar este link : <TMPL_VAR url>).
+
+Gracias
+</textarea>
+</td></tr></table>
+<input class='formulaire' type='submit' name='action' value='move_email'>
+</form>
+<br>
+<a href="<TMPL_VAR url>"><img alt='update now' src='/bweb/update.png'>Actualizar Ahora</a>
+</div>
diff --git a/gui/bweb/lang/es/tpl/client_job_status.tpl b/gui/bweb/lang/es/tpl/client_job_status.tpl
new file mode 100644 (file)
index 0000000..ecd64e1
--- /dev/null
@@ -0,0 +1,40 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> 
+       Job ejecutándose <TMPL_VAR JobName> en <TMPL_VAR Client>
+  </h1>
+ </div>
+ <div class='bodydiv'>
+
+<table>
+ <tr>
+  <td> <b> Nombre Job: </b> <td> <td> <TMPL_VAR jobname> (<TMPL_VAR jobid>) <td> 
+ </tr>
+ <tr>
+  <td> <b> Archivo en proceso: </b> <td> <td> <TMPL_VAR "processing file"> </td>
+ </tr>
+ <tr>
+  <td> <b> Velocidad: </b> <td> <td> <TMPL_VAR "bytes/sec"> B/s</td>
+ </tr>
+ <tr>
+  <td> <b> Archivos Examinados: </b> <td> <td> <TMPL_VAR "files examined"></td>
+ </tr>
+ <tr>
+  <td> <b> Bytes: </b> <td> <td> <TMPL_VAR bytes></td>
+ </tr>
+</table>
+<form name='form1' action='?' method='GET'>
+<input type="image" name='action' value='dsp_cur_job' 
+ src='/bweb/update.png' title='refresh'>&nbsp;
+<input type='hidden' name='client' value='<TMPL_VAR Client>'>
+<input type='hidden' name='jobid' value='<TMPL_VAR JobId>'>
+<input type="image" name='action' value='cancel_job'
+       onclick="return confirm('Do you want to cancel this job ?')"
+        title='Cancel job' src='/bweb/cancel.png'>&nbsp;
+</form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+  bweb_add_refresh();
+</script>
+
diff --git a/gui/bweb/lang/es/tpl/client_list.tpl b/gui/bweb/lang/es/tpl/client_list.tpl
new file mode 100644 (file)
index 0000000..b200cf9
--- /dev/null
@@ -0,0 +1,70 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Clientes</h1>
+ </div>
+ <div class='bodydiv'>
+<form action='?' method='GET'>
+     <table id='id<TMPL_VAR NAME=ID>'></table>
+       <div class="otherboxtitle">
+          Acciones &nbsp;
+        </div>
+        <div class="otherbox">
+<!--        <h1>Acciones</h1> -->      
+       <label>
+       <input type="image" name='action' value='job' title='Mostrar Ãºltimos jobs' src='/bweb/zoom.png'>Últimos Jobs</label> &nbsp;
+       <label>
+       <input type="image" name='action' value='dsp_cur_job' title='Mostrar job actual' src='/bweb/zoom.png'>Jobs Actuales</label> &nbsp;
+       <label>
+       <input type="image" name='action' value='client_status' title='Mostrar estado del cliente' src='/bweb/zoom.png'>Estado</label> &nbsp;
+       <label>
+       <input type="image" name='action' value='client_stats' title='Estadísticas del Cliente' src='/bweb/chart.png'>Estadísticas</label> &nbsp;
+       </label>
+        </div>
+
+</form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+var header = new Array("Nombre", "Selección", "Descripción", "Auto Prune", "Retención Archivos", "Retención Jobs");
+
+var data = new Array();
+var chkbox ;
+
+<TMPL_LOOP NAME=Clients>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.name = 'client';
+chkbox.value = '<TMPL_VAR NAME=Name>';
+
+data.push( 
+  new Array( "<TMPL_VAR NAME=Name>", 
+             chkbox,
+            "<TMPL_VAR NAME=Uname>",
+            "<TMPL_VAR NAME=AutoPrune>",
+            human_sec(<TMPL_VAR NAME=FileRetention>),
+            human_sec(<TMPL_VAR NAME=JobRetention>)
+              )
+) ; 
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR NAME=ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+ disable_sorting: new Array(1)
+}
+);
+</script>
diff --git a/gui/bweb/lang/es/tpl/command.tpl b/gui/bweb/lang/es/tpl/command.tpl
new file mode 100644 (file)
index 0000000..ce9a906
--- /dev/null
@@ -0,0 +1,9 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> <TMPL_VAR title> : <TMPL_VAR name></h1>
+ </div>
+ <div class='bodydiv'>
+  <pre id='log' style='font-size: 10px'>
+<TMPL_VAR content>
+  </pre>
+ </div>
diff --git a/gui/bweb/lang/es/tpl/config_edit.tpl b/gui/bweb/lang/es/tpl/config_edit.tpl
new file mode 100644 (file)
index 0000000..a385a40
--- /dev/null
@@ -0,0 +1,50 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Configuración </h1>
+</div>
+<div class='bodydiv'>
+   <form action="?" method='post'>
+    <table>
+     <tr>  <td><b>SQL Connection</b></td>  <td/></tr>
+     <tr><td>DBI :</td>     
+         <td> 
+          <input class="formulaire" type='text' value='<TMPL_VAR dbi>' size='64' name='dbi'> 
+         </td>
+     </tr>
+     <tr><td>Usuario :</td> 
+         <td> <input class="formulaire" type='text' value='<TMPL_VAR user>' name='user'>
+         </td>
+     </tr>
+     <tr><td>Clave :</td> 
+         <td> <input class="formulaire" type='password' value='<TMPL_VAR password>' name='password'> 
+         </td></tr>
+
+     <tr>  <td><b>Opciones Generales</b></td>  <td/></tr>
+
+     <tr><td>email_media :</td> 
+         <td> <input class="formulaire" type='text' value='<TMPL_VAR email_media>' name='email_media'> 
+         </td></tr>
+         </td></tr>
+
+     <tr>  <td><b>Configuración Bweb</b></td>  <td/></tr>
+
+     <tr><td>graph_font :</td> 
+         <td> <input class="formulaire" type='text' value='<TMPL_VAR graph_font>' size='64' name='graph_font'> 
+         </td></tr>
+     <tr><td>template_dir :</td> 
+         <td> <input class="formulaire" type='text' value='<TMPL_VAR template_dir>' size='64' name='template_dir'> 
+         </td></tr>
+     <tr><td>fv_write_path :</td> 
+         <td> <input class="formulaire" title="Este directorio debe tener permisos de escritura para el usuario apache y debe ser accesible en /bweb/fv" type='text' value='<TMPL_VAR fv_write_path>' size='64' name='fv_write_path'> 
+         </td></tr>
+     <tr><td>bconsole :</td> 
+         <td> <input class="formulaire" type='text' value='<TMPL_VAR bconsole>' size='64' name='bconsole'> 
+         </td></tr>
+     <tr><td>debug :</td> 
+         <td> <input class="formulaire" type='checkbox' name='debug' <TMPL_IF debug> checked='checked' value='on' </TMPL_IF> > 
+         </td></tr>
+    </table>
+    <input type="image" name='action' value='apply_conf' src='/bweb/save.png'>
+   </form>
+</div>
diff --git a/gui/bweb/lang/es/tpl/config_view.tpl b/gui/bweb/lang/es/tpl/config_view.tpl
new file mode 100644 (file)
index 0000000..e20ebc5
--- /dev/null
@@ -0,0 +1,62 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Configuración </h1>
+</div>
+<div class='bodydiv'>
+   <table>
+    <tr>  <td><b>Conexión SQL</b></td>  <td/></tr>
+    <tr><td>DBI :</td>      <td> <TMPL_VAR dbi>      </td></tr>
+    <tr><td>Ususario :</td>     <td> <TMPL_VAR user>     </td></tr>
+    <tr><td>Clave :</td> <td> xxxxx </td></tr>
+    <tr>  <td><b>Opciones Generales</b></td>  <td/></tr>
+    <tr><td>email_media :</td> <td> <TMPL_VAR email_media> </td></tr>
+    <tr>  <td><b>Configuración Bweb</b></td>  <td/></tr>
+    <tr><td>config_file :</td> <td> <TMPL_VAR config_file> </td></tr>
+    <tr><td title="/path/a/tu/template_dir">template_dir :</td> <td> <TMPL_VAR template_dir> </td></tr>
+    <tr><td title="/path/a/a/font.ttf">graph_font :</td> <td> <TMPL_VAR graph_font> </td></tr>
+    <tr><td title="Este directorio debe tener permisos de escritura para el usuario apache y debe ser accesible en /bweb/fv">fv_write_path :</td> <td> <TMPL_VAR fv_write_path> </td></tr>
+    <tr><td title="/path/a/bconsole -n -c /path/to/bconsole.conf">bconsole :</td> <td> <TMPL_VAR bconsole> </td></tr>
+    <tr><td>debug :</td> <td> <TMPL_VAR debug> </td></tr>
+    <TMPL_IF achs>
+    <tr>  <td><b>Libreria</b></td>  <td/></tr>
+    <tr>
+     <td>
+     <form action='?' method='GET'>
+     <table border='0'>
+    <TMPL_LOOP achs>
+      <tr> 
+       <td>
+<label>
+ <input type='radio' name='ach' value='<TMPL_VAR name>'><TMPL_VAR name>
+</label>
+       </td>
+      </tr>
+    </TMPL_LOOP>
+    </table>
+   <td>
+  
+   <input type="image" name="action" value="ach_edit" title="editar" src='/bweb/edit.png'> 
+   <input type="image" name='action' value='ach_del' title='borrar' src='/bweb/remove.png'>
+   <input type='image' name='action' value='ach_view' title='ver' src='/bweb/zoom.png'>
+    </form>
+    </td>
+   </tr>
+   </TMPL_IF achs>
+   <tr>
+   <td><hr></td><td></td>
+   </tr>
+  </table>
+
+  <form action='?' method='GET'>
+   <label>
+   <input name='action' value='edit_conf' type="image" title='Edit' src='/bweb/edit.png'> Editar
+   </label>
+   <label>
+   <input name='action' value='ach_add' type="image" title='Add an autochanger' src='/bweb/add.png'> Agregar libreria
+   </label>
+  </form>
+
+  <TMPL_IF error>
+  info :  <TMPL_VAR error> </br>
+  </TMPL_IF>
+</div>
diff --git a/gui/bweb/lang/es/tpl/display_client_job.tpl b/gui/bweb/lang/es/tpl/display_client_job.tpl
new file mode 100644 (file)
index 0000000..ba62845
--- /dev/null
@@ -0,0 +1,65 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Ã¼ltimos jobs de <TMPL_VAR clientname> (<TMPL_VAR Filter>)
+  </h1>
+ </div>
+ <div class='bodydiv'>
+
+   <table id='id<TMPL_VAR ID>'></table>
+
+<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_size;status=T">
+    <img src="/bweb/chart.png" alt="backup size" title="backup size evolution"/>
+    </a>
+<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_duration;status=T">
+    <img src="/bweb/chart.png" alt="backup duration" title="backup time evolution"/>
+    </a>
+<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_rate;status=T">
+    <img src="/bweb/chart.png" alt="backup rate" title="backup rate evolution"/>
+    </a>                               
+ </div>
+
+
+<script type="text/javascript" language="JavaScript">
+var header = new Array("IdJob", "Nombre Job", "File Set", "Nivel", "Tiempo Inicio", 
+                  "Archivos Job", "Bytes Job", "Errors");
+
+var data = new Array();
+
+<TMPL_LOOP Jobs>
+data.push( new Array(
+"<TMPL_VAR JobId>",
+"<TMPL_VAR JobName>",    
+"<TMPL_VAR FileSet>",
+"<TMPL_VAR Level>",
+"<TMPL_VAR StartTime>",
+"<TMPL_VAR JobFiles>",   
+human_size(<TMPL_VAR JobBytes>),
+"<TMPL_VAR JobErrors>"   
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: true,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+ disable_sorting: new Array(5,6)
+}
+);
+
+// get newest job first
+nrsTables['id<TMPL_VAR ID>'].fieldSort(0);
+</script>
diff --git a/gui/bweb/lang/es/tpl/display_client_stats.tpl b/gui/bweb/lang/es/tpl/display_client_stats.tpl
new file mode 100644 (file)
index 0000000..da4f445
--- /dev/null
@@ -0,0 +1,59 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Cliente : <TMPL_VAR NAME=clientname> (<TMPL_VAR NAME=label>)</h1>
+ </div>
+ <div class='bodydiv'>
+<form action='?'
+     <table id='id<TMPL_VAR NAME=ID>'></table>
+     <img src="bgraph.pl?client=<TMPL_VAR NAME=clientname>;graph=job_duration;age=2592000;width=420;height=200" alt='Not enough data' > &nbsp;
+     <img src="bgraph.pl?client=<TMPL_VAR NAME=clientname>;graph=job_rate;age=2592000;width=420;height=200" alt='Not enough data'> &nbsp;
+     <img src="bgraph.pl?client=<TMPL_VAR NAME=clientname>;graph=job_size;age=2592000;width=420;height=200" alt='Not enough data'> &nbsp;
+<!--   <div class="otherboxtitle">
+          Actions &nbsp;
+        </div>
+        <div class="otherbox">
+       <h1>Acciones</h1> 
+       <input type="image" name='action' value='job' title='Mostrar Ãºltimo job'
+        src='/bweb/zoom.png'> &nbsp;
+       <input type="image" name='action' value='dsp_cur_job' title='Mostrar job actual' src='/bweb/zoom.png'> &nbsp;
+       <input type="image" name='action' value='client_stat' title='Estadísticas Cliente' src='/bweb/zoom.png'> &nbsp;
+        </div>
+-->
+</form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+var header = new Array("Nombre", "Nb Jobs", "Nb Bytes", "Nb Files", "Nb Errors");
+
+var data = new Array();
+
+data.push( 
+  new Array( "<TMPL_VAR NAME=clientname>", 
+            "<TMPL_VAR NAME=nb_jobs>",
+            human_size(<TMPL_VAR NAME=nb_bytes>),
+            "<TMPL_VAR NAME=nb_files>",
+            "<TMPL_VAR NAME=nb_err>"
+             )
+) ; 
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR NAME=ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+// disable_sorting: new Array(1),
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/lang/es/tpl/display_form_job.tpl b/gui/bweb/lang/es/tpl/display_form_job.tpl
new file mode 100644 (file)
index 0000000..75acd9c
--- /dev/null
@@ -0,0 +1,126 @@
+<br/>
+<div class="otherboxtitle">
+  Filter &nbsp;
+</div>
+<div class="otherbox">
+<form name='form1' action='?' method='GET'>
+<table border='0'>
+<tr>
+  <td valign='top'>
+    <h2>Nivel</h2>
+    <select name='level' class='formulaire'>
+      <option id='level_Any' value='Any'>Cualquiera</option>
+      <option id='level_F' value='F'>Completo</option>
+      <option id='level_D' value='D'>Diferencial</option>
+      <option id='level_I' value='I'>Incremental</option>
+    </select>     
+  </td>
+</tr>
+<tr>
+ <td valign='top'>
+    <h2>Estado</h2>
+    <select name='status' class='formulaire'>
+      <option id='status_Any' value='Any'>Cualquiera</option>
+      <option id='status_T'   value='T'>Ok</option>
+      <option id='status_f'   value='f'>Error</option>
+      <option id='status_A'   value='A'>Cancelados</option>
+    </select>     
+  </td>
+</tr>
+<tr>
+ <td valign='top'>
+    <h2>Pool</h2>
+    <select name='pool' class='formulaire'>
+      <option id='pool_all' value=''>Todos</option>
+<TMPL_LOOP NAME=db_pools>
+      <option id='pool_<TMPL_VAR name>'><TMPL_VAR name></option>
+</TMPL_LOOP>
+    </select>
+  </td>
+</tr>
+<tr>
+  <td valign='top'>
+    <h2>Tiempo</h2>
+    <select name='age' class='formulaire'>
+      <option id='age_604800'   value='604800'>Esta semana</option>
+      <option id='age_2678400'  value='2678400'>Últimos 30 dias</option>
+      <option id='age_15552000' value='15552000'>Últimos 6 meses</option>
+    </select>     
+  </td>
+ </tr>
+ <tr>
+  <td valign='bottom'> 
+    <h2>Number of items</h2>
+    <input type='text' name='limit' value='<TMPL_VAR NAME=limit>' 
+       class='formulaire' size='4'>
+  </td>
+</tr>
+<tr>
+  <td valign='top'> 
+    <h2>Tipo Job</h2>
+    <select name='jobtype' class='formulaire'>
+      <option id='jobtype_any' value='all type'>Cualquiera</option>
+      <option id='jobtype_B' value='B'>Backup</option>
+      <option id='jobtype_R' value='R'>Recuperación</option>
+    </select>
+  </td>
+</tr>
+<tr>
+  <td valign='top'> 
+    <h2>Clientes</h2>
+    <select name='client' size='15' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_clients>
+      <option id='client_<TMPL_VAR clientname>'><TMPL_VAR clientname></option>
+</TMPL_LOOP>
+    </select>
+  </td>
+</tr>
+<!--
+<tr>
+  <td valign='top'> 
+    <h2>FileSet</h2>
+    <select name='fileset' size='15' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_filesets>
+      <option id='client_<TMPL_VAR fileset>'><TMPL_VAR NAME=fileset></option>
+</TMPL_LOOP>
+    </select>
+  </td>
+</tr>
+-->
+</table>
+  <input type="image" name='action' value='job' src='/bweb/update.png'>
+
+</form>
+</div>
+<script type="text/javascript" language="JavaScript">
+
+  <TMPL_LOOP qclients>
+     document.getElementById('client_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+  <TMPL_IF status>
+     document.getElementById('status_<TMPL_VAR status>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF level>
+     document.getElementById('level_<TMPL_VAR level>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF age>
+     document.getElementById('age_<TMPL_VAR age>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF jobtype>
+     document.getElementById('jobtype_<TMPL_VAR jobtype>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_LOOP qfilesets>
+     document.getElementById('fileset_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+  <TMPL_LOOP qpools>
+     document.getElementById('pool_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+</script>
+
diff --git a/gui/bweb/lang/es/tpl/display_form_media.tpl b/gui/bweb/lang/es/tpl/display_form_media.tpl
new file mode 100644 (file)
index 0000000..fccaa31
--- /dev/null
@@ -0,0 +1,91 @@
+<div class="otherboxtitle">
+  Filter &nbsp;
+</div>
+<div class="otherbox">
+<form name='form1' action='?' method='GET'>
+<table border='0'>
+<tr>
+  <td valign='top'>
+    <h2>Tipo Medio</h2>
+    <select name='mediatype' class='formulaire'>
+      <option id='mediatype_all' value=''></option>
+<TMPL_LOOP NAME=db_mediatypes>
+      <option id='mediatype_<TMPL_VAR mediatype>'><TMPL_VAR mediatype></option>
+</TMPL_LOOP>
+    </select>     
+  </td>
+</tr>
+<tr>
+  <td valign='top'>
+    <h2>Ubicación</h2>
+    <select name='location' class='formulaire'>
+      <option id='location_all>' value=''></option>
+<TMPL_LOOP NAME=db_locations>
+      <option id='location_<TMPL_VAR location>'><TMPL_VAR location></option>
+</TMPL_LOOP>
+    </select>     
+  </td>
+</tr>
+<tr>
+ <td valign='top'>
+    <h2>Estado</h2>
+    <select name='volstatus' class='formulaire'>
+      <option id='volstatus_All' value=''></option>
+      <option id='volstatus_Append' value='Append'>Abierta</option>
+      <option id='volstatus_Full'   value='Full'>Llena</option>
+      <option id='volstatus_Error'  value='Error'>Error</option>
+      <option id='volstatus_Used'   value='Used'>Usada</option>
+      <option id='volstatus_Purged' value='Purged'>Purgada</option>
+    </select>     
+  </td>
+</tr>
+<tr>
+ <td valign='top'>
+    <h2>Pool</h2>
+    <select name='pool' class='formulaire'>
+      <option id='pool_all>' value=''></option>
+<TMPL_LOOP NAME=db_pools>
+      <option id='pool_<TMPL_VAR name>'><TMPL_VAR name></option>
+</TMPL_LOOP>
+    </select>     
+  </td>
+</tr>
+ <tr>
+  <td valign='bottom'> 
+    <h2>Nombre</h2>
+    <input type='text' name='re_media' 
+      <TMPL_IF qre_media>value=<TMPL_VAR qre_media></TMPL_IF>
+       class='formulaire' size='8'>
+  </td>
+</tr>
+ <tr>
+  <td valign='bottom'> 
+    <h2>Number of items</h2>
+    <input type='text' name='limit' value='<TMPL_VAR limit>' 
+       class='formulaire' size='4'>
+  </td>
+</tr>
+
+</table>
+  <input type="image" name='action' value='media' src='/bweb/update.png'>
+
+</form>
+</div>
+<script type="text/javascript" language="JavaScript">
+  <TMPL_IF volstatus>
+     document.getElementById('volstatus_<TMPL_VAR volstatus>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_LOOP qmediatypes>
+     document.getElementById('mediatype_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+  <TMPL_LOOP qpools>
+     document.getElementById('pool_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+  <TMPL_LOOP qlocations>
+     document.getElementById('location_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+</script>
+
diff --git a/gui/bweb/lang/es/tpl/display_job.tpl b/gui/bweb/lang/es/tpl/display_job.tpl
new file mode 100644 (file)
index 0000000..73d97ab
--- /dev/null
@@ -0,0 +1,81 @@
+ <div class='titlediv'>
+  <h1 class='newstitle'> Ãšltimos Jobs (<TMPL_VAR Filter>)</h1>
+ </div>
+ <div class='bodydiv'>
+    <table id='id<TMPL_VAR ID>'></table>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+<TMPL_IF status>
+document.getElementById('status_<TMPL_VAR status>').checked = true;
+</TMPL_IF>
+
+
+
+var header = new Array("IdJob",
+                      "Cliente",
+                      "Nombre Job", 
+                      "FileSet",
+//                     "Pool",
+                       "Nivel",
+                       "Inicio",
+                      "Duración",
+                       "Archivos Job",
+                       "Bytes Job", 
+                       "Errores",
+                      "Estado");
+
+var data = new Array();
+
+<TMPL_LOOP Jobs>
+a = document.createElement('A');
+a.href='?action=job_zoom;jobid=<TMPL_VAR JobId>';
+
+img = document.createElement("IMG");
+img.src=bweb_get_job_img("<TMPL_VAR JobStatus>", <TMPL_VAR joberrors>);
+img.title=jobstatus['<TMPL_VAR JobStatus>']; 
+
+a.appendChild(img);
+
+data.push( new Array(
+"<TMPL_VAR JobId>",
+"<TMPL_VAR Client>",     
+"<TMPL_VAR JobName>",    
+"<TMPL_VAR FileSet>",    
+//"<TMPL_VAR Pool>",
+"<TMPL_VAR Level>",      
+"<TMPL_VAR StartTime>",
+"<TMPL_VAR Duration>",
+"<TMPL_VAR JobFiles>",   
+human_size(<TMPL_VAR JobBytes>),
+"<TMPL_VAR joberrors>",   
+a
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: true,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+ disable_sorting: new Array(10),
+ padding: 3
+}
+);
+
+// get newest backup first
+nrsTables['id<TMPL_VAR ID>'].fieldSort(0);
+</script>
diff --git a/gui/bweb/lang/es/tpl/display_job_zoom.tpl b/gui/bweb/lang/es/tpl/display_job_zoom.tpl
new file mode 100644 (file)
index 0000000..fd9f86b
--- /dev/null
@@ -0,0 +1,129 @@
+ <div class='titlediv'>
+  <h1 class='newstitle'>Información acerca jobs</h1>
+ </div>
+ <div class="bodydiv">
+ <table id='id0'></table>
+ <table><td>
+ <form action='bweb.pl?'>
+  <input type='hidden' name='jobid' value='<TMPL_VAR jobid>'>
+  <label>
+  <input type="image" name='action' value='delete' title='delete this job'
+ onclick="return confirm('¿ Seguro quiere borrar este job del catálogo ?');"
+   src='/bweb/purge.png'> Borrar
+  </label>
+ </form>
+ </td><td>
+ <form action='bweb.pl?'>
+  <TMPL_LOOP volumes>
+   <input type='hidden' name='media' value='<TMPL_VAR VolumeName>'>
+  </TMPL_LOOP>   
+  <label>
+  <input type="image" name='action' value='media' title='view media' 
+   src='/bweb/zoom.png'>Ver medio
+  </label>
+ </form>
+ </td>
+ <td>
+ <form action='bweb.pl?'>
+  <input type='hidden' name='client' value='<TMPL_VAR Client>'>
+  <label>
+  <input type="image" name='action' value='job' title='view <TMPL_VAR Client> jobs' src='/bweb/zoom.png'>Ver jobs
+  </label>
+ </form>
+ </td>
+ <td>
+ <form action='bweb.pl?'>
+  <input type='hidden' name='age' value='2678400'>
+  <input type='hidden' name='client' value='<TMPL_VAR Client>'>
+  <input type='hidden' name='jobname' value='<TMPL_VAR jobname>'>
+  <label>
+  <input type="image" name='action' value='graph' title='view trends'
+   src='/bweb/chart.png'> Ver estadísticas
+  </label>
+ </form>
+ </td>
+ <td>
+ <form action='bweb.pl?'>
+  <input type='hidden' name='fileset' value='<TMPL_VAR FileSet>'>
+  <label>
+  <input type="image" name='action' value='fileset_view' title='view fileset'
+   src='/bweb/zoom.png'> Ver FileSet
+  </label>
+ </form>
+ </td>
+<!-- Remove this to activate bfileview -->
+ <td>
+ <form action='bfileview.pl?'>
+  <input type='hidden' name='jobid' value='<TMPL_VAR jobid>'>
+  <input type='hidden' name='where' value='/'>
+  <label>
+  <input type="image" name='action' value='bfileview' title='view file usage'
+   src='/bweb/colorscm.png' onclick='if (<TMPL_VAR JobFiles> > 50000) { return confirm("Puede demorar, Â¿ Seguro quiere continuar ?")} else { return 1; }'> Ver uso de archivos
+  </label>
+ </form>
+ </td>
+<!-- -->
+ </table>
+</div>
+
+<script type="text/javascript" language='JavaScript'>
+var header = new Array("IdJob",
+                      "Cliente",
+                      "Nombre Job", 
+                      "FileSet",
+                       "Nivel",
+                       "Inicio", 
+                      "Duración",
+                       "Archivos Job",
+                       "Bytes Job",
+                       "Errores",
+                      "Pool",
+                       "Nombre Volumen",
+                      "Estado");
+
+var data = new Array();
+
+img = document.createElement("IMG");
+img.src=bweb_get_job_img("<TMPL_VAR JobStatus>", <TMPL_VAR joberrors>);
+img.title=jobstatus['<TMPL_VAR JobStatus>']; 
+
+data.push( new Array(
+"<TMPL_VAR JobId>",
+"<TMPL_VAR Client>",     
+"<TMPL_VAR JobName>",    
+"<TMPL_VAR FileSet>",    
+"<TMPL_VAR Level>",      
+"<TMPL_VAR StartTime>",
+"<TMPL_VAR duration>",
+"<TMPL_VAR JobFiles>",   
+human_size(<TMPL_VAR JobBytes>),
+"<TMPL_VAR joberrors>",
+"<TMPL_VAR poolname>",
+"<TMPL_LOOP volumes><TMPL_VAR VolumeName>\n</TMPL_LOOP>",   
+img
+ )
+);
+
+nrsTable.setup(
+{
+ table_name:     "id0",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: true,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+// disable_sorting: new Array(6)
+ padding: 3
+}
+);
+
+</script>
diff --git a/gui/bweb/lang/es/tpl/display_location.tpl b/gui/bweb/lang/es/tpl/display_location.tpl
new file mode 100644 (file)
index 0000000..14c1d2f
--- /dev/null
@@ -0,0 +1,66 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'>Ubicaciones</h1>
+ </div>
+ <div class="bodydiv">
+   <form action='?' method='get'>
+    <table id='id<TMPL_VAR ID>'></table>
+    <input type="image" name='action' value='location_add' title='Agregar Ubicación' src='/bweb/add.png'>&nbsp;
+    <input type="image" name='action' value='location_del' title='Remover Ubicación' src='/bweb/remove.png'>&nbsp;
+    <input type="image" name='action' value='location_edit' title='Editar Ubicación' src='/bweb/edit.png'>&nbsp;
+
+    <input type="image" name='action' value='media' title='Mostrar contenido'
+     src='/bweb/zoom.png'>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Nombre","Activado", "Cost", "Nb volumes", "Selección");
+
+var data = new Array();
+var chkbox;
+
+var img;
+
+<TMPL_LOOP Locations>
+img = document.createElement('IMG');
+img.src = '/bweb/inflag<TMPL_VAR enabled>.png';
+
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'radio';
+chkbox.name  = 'location';
+chkbox.value = '<TMPL_VAR Location>';
+
+data.push( new Array(
+"<TMPL_VAR Location>",
+img,
+"<TMPL_VAR Cost>",
+"<TMPL_VAR name=volnum>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6),
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/lang/es/tpl/display_log.tpl b/gui/bweb/lang/es/tpl/display_log.tpl
new file mode 100644 (file)
index 0000000..f71f209
--- /dev/null
@@ -0,0 +1,9 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Log : <TMPL_VAR name> en <TMPL_VAR client> (<TMPL_VAR jobid>)</h1>
+ </div>
+ <div class='bodydiv'>
+  <pre id='log'>
+<TMPL_VAR lines>
+  </pre>
+ </div>
diff --git a/gui/bweb/lang/es/tpl/display_media.tpl b/gui/bweb/lang/es/tpl/display_media.tpl
new file mode 100644 (file)
index 0000000..f803c6e
--- /dev/null
@@ -0,0 +1,91 @@
+ <div class='titlediv'>
+  <h1 class='newstitle'> 
+   Medios
+  </h1>
+ </div>
+ <div class='bodydiv'>
+
+<TMPL_IF Pool>
+<h2>
+Pool : <a href="?action=pool;pool=<TMPL_VAR Pool>">
+         <TMPL_VAR Pool>
+       </a>
+</h2>
+</TMPL_IF>
+<TMPL_IF Location>
+<h2>
+Location : <TMPL_VAR location>
+</h2>
+</TMPL_IF>
+
+   <form action='?action=test' method='get'>
+    <table id='id_pool_<TMPL_VAR ID>'></table>
+      <input type="image" name='action' value='extern' title='Move out' src='/bweb/extern.png' onclick='return confirm("¿Seguro quiere expulsar el medio seleccionado?");'>&nbsp;
+      <input type="image" name='action' value='intern' title='Move in' src='/bweb/intern.png'>&nbsp;
+      <input type="image" name='action' value='update_media' title='Update medium' src='/bweb/edit.png'>&nbsp;
+      <input type="image" name='action' value='media_zoom' title='Informations' src='/bweb/zoom.png'>&nbsp;
+<!--
+      <input type="image" name='action' value='purge' title='Purge' src='/bweb/purge.png'>&nbsp;
+-->
+      <input type="image" name='action' value='prune' title='Prune' src='/bweb/prune.png'>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Nombre Volumen","Online","Bytes Vol", "Uso Vol", "Estado Vol",
+                      "Pool", "Tipo Medio",
+                      "Fecha Escritura", "Expiración", "Selección");
+
+var data = new Array();
+var img;
+var chkbox;
+var d;
+
+<TMPL_LOOP Medias>
+d = percent_usage(<TMPL_VAR volusage>);
+
+img = document.createElement('IMG');
+img.src = '/bweb/inflag<TMPL_VAR online>.png';
+
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.name = 'media';
+chkbox.value = '<TMPL_VAR volumename>';
+
+data.push( new Array(
+"<TMPL_VAR volumename>",
+img,
+human_size(<TMPL_VAR volbytes>),
+d,
+"<TMPL_VAR volstatus>",
+"<TMPL_VAR poolname>",
+"<TMPL_VAR mediatype>",
+"<TMPL_VAR lastwritten>",
+"<TMPL_VAR expire>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id_pool_<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+ rows_per_page: rows_per_page,
+ disable_sorting: new Array(1,3,9)
+}
+);
+</script>
diff --git a/gui/bweb/lang/es/tpl/display_media_zoom.tpl b/gui/bweb/lang/es/tpl/display_media_zoom.tpl
new file mode 100644 (file)
index 0000000..6f7b564
--- /dev/null
@@ -0,0 +1,163 @@
+<table>
+<td valign='top'>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Medium : <TMPL_VAR volumename> <TMPL_VAR comment></h1>
+ </div>
+ <div class='bodydiv'>
+    <b> Medium Infos</b><br/>
+    <table id='id_info_<TMPL_VAR volumename>'></table>
+    <b> Medium Stats</b><br/>
+    <table id='id_media_<TMPL_VAR volumename>'></table>
+    <b> Job List </b></br>
+    <table id='id_jobs_<TMPL_VAR volumename>'></table>
+    <b> Actions </b></br>
+   <form action='?' method='get'>
+      <input type='hidden' name='media' value='<TMPL_VAR volumename>'>
+<TMPL_IF online>&nbsp;
+      <input type="image" name='action' value='extern' onclick='return confirm("Do you want to eject this medium ?");' title='move out' src='/bweb/extern.png'>&nbsp;
+<TMPL_ELSE>
+      <input type="image" name='action' value='intern' title='move in' src='/bweb/intern.png'>&nbsp;
+</TMPL_IF>
+      <input type="image" name='action' value='update_media' title='Update' src='/bweb/edit.png'>&nbsp;
+      <input type="image" name='action' value='purge' title='Purge' src='/bweb/purge.png' onclick="return confirm('Do you want to purge this volume ?')">&nbsp;
+      <input type="image" name='action' value='prune' title='Prune' src='/bweb/prune.png'>&nbsp;
+<TMPL_IF Locationlog>
+      <a href='#' onclick='document.getElementById("locationlog").style.visibility="visible";'><img title='View location log' src='/bweb/zoom.png'></a>
+</TMPL_IF>
+   </form>
+ </div>
+</td>
+<td valign='top'style="visibility:hidden;" id='locationlog'>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Location log </h1>
+ </div>
+ <div class='bodydiv'>
+<pre>
+ <TMPL_VAR LocationLog>
+</pre>
+ </div>
+</td>
+</table>
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Pool","Online","Location","Vol Status", "Vol Bytes", "Expire",
+                      "Retention","Max use duration", "Max jobs" );
+
+var data = new Array();
+var img;
+
+img = document.createElement('IMG');
+img.src = '/bweb/inflag<TMPL_VAR online>.png';
+
+data.push( new Array(
+"<TMPL_VAR poolname>",
+img,
+"<TMPL_VAR location>",
+"<TMPL_VAR volstatus>",
+human_size(<TMPL_VAR nb_bytes>),
+"<TMPL_VAR expire>",
+human_sec(<TMPL_VAR volretention>),
+human_sec(<TMPL_VAR voluseduration>),
+"<TMPL_VAR maxvoljobs>"
+ )
+);
+
+nrsTable.setup(
+{
+ table_name:     "id_info_<TMPL_VAR volumename>",
+ table_header: header,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+ table_data: data,
+ header_color: header_color,
+ padding: 3,
+ disable_sorting: new Array(1)
+}
+);
+
+var header = new Array( "Vol Mounts", "Recycle count", "Read time", "Write time", "Errors");
+
+var data = new Array();
+data.push( new Array(
+"<TMPL_VAR nb_mounts>",
+"<TMPL_VAR recyclecount>",
+human_sec(<TMPL_VAR volreadtime>),
+human_sec(<TMPL_VAR volwritetime>),
+"<TMPL_VAR nb_errors>"
+ )
+);
+
+nrsTable.setup(
+{
+ table_name:     "id_media_<TMPL_VAR volumename>",
+ table_header: header,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+ table_data: data,
+ header_color: header_color,
+// disable_sorting: new Array()
+ padding: 3
+}
+);
+
+
+var header = new Array("IdJob","Nombre","Inicio","Tipo",
+                      "Nivel", "Archivos", "Bytes", "Estado");
+
+var data = new Array();
+var a;
+var img;
+
+<TMPL_LOOP jobs>
+a = document.createElement('A');
+a.href='?action=job_zoom;jobid=<TMPL_VAR JobId>';
+
+img = document.createElement("IMG");
+img.src="/bweb/<TMPL_VAR status>.png";
+img.title=jobstatus['<TMPL_VAR status>']; 
+
+a.appendChild(img);
+
+data.push( new Array(
+"<TMPL_VAR jobid>",
+"<TMPL_VAR name>",
+"<TMPL_VAR starttime>",
+"<TMPL_VAR type>",
+"<TMPL_VAR level>",
+"<TMPL_VAR files>",
+human_size(<TMPL_VAR bytes>),
+a
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id_jobs_<TMPL_VAR volumename>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6),
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/lang/es/tpl/display_pool.tpl b/gui/bweb/lang/es/tpl/display_pool.tpl
new file mode 100644 (file)
index 0000000..e1d3fd7
--- /dev/null
@@ -0,0 +1,88 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'>Pools</h1>
+ </div>
+ <div class="bodydiv">
+   <form action='?' method='get'>
+    <table id='id<TMPL_VAR ID>'></table>
+    <input type="image" type='submit' name='action' value='media' title='Mostrar contenido' src='/bweb/zoom.png'>
+<TMPL_LOOP MediaType>
+    <input type='hidden' name='mediatype' value=<TMPL_VAR name>>
+</TMPL_LOOP>
+   </form>
+   <br/>
+   Nota: Para modificar las propiedades de un pool, se debe editar la configuración de Bacula
+   y aplicar el comando "reload", Luego se debe ejecutar "update pool=mypool" con la bconsole.
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Nombre","Reciclado","Retención","Use Duration",
+                       "Máx Jobs/Volumen","Máx Archivos/Volumen", 
+                       "Máx Tamaño/Volumen","Nb volumes", "Estado Volumen", "Uso", "Selección");
+
+var data = new Array();
+var chkbox;
+var img;
+var img2;
+
+<TMPL_LOOP Pools>
+
+img = percent_display([
+<TMPL_IF nb_recycle>{ name: "Reciclado", nb: <TMPL_VAR nb_recycle> },</TMPL_IF>
+<TMPL_IF nb_purged> { name: "Purgado", nb: <TMPL_VAR nb_purged> },</TMPL_IF>
+<TMPL_IF nb_append> { name: "Abierto", nb: <TMPL_VAR nb_append> },</TMPL_IF>
+<TMPL_IF nb_full>   { name: "Lleno", nb: <TMPL_VAR nb_full> },    </TMPL_IF>
+<TMPL_IF nb_disabled>   { name: "Disactivado", nb: <TMPL_VAR nb_disabled> },    </TMPL_IF>
+<TMPL_IF nb_error>  { name: "Error", nb: <TMPL_VAR nb_error> },  </TMPL_IF>
+<TMPL_IF nb_archive>{ name: "Archivado", nb: <TMPL_VAR nb_archive> },</TMPL_IF>
+<TMPL_IF nb_used>   { name: "Usado", nb: <TMPL_VAR nb_used> },    </TMPL_IF>
+<TMPL_IF NAME='nb_read-only'> { name: "Lectura", nb: <TMPL_VAR NAME='nb_read-only'> }, </TMPL_IF>
+{}
+]);
+
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'radio';
+chkbox.value = '<TMPL_VAR Name>';
+chkbox.name  = 'pool';
+
+img2 = percent_usage(<TMPL_VAR poolusage>);
+
+data.push( new Array(
+"<TMPL_VAR Name>",
+"<TMPL_VAR Recycle>",
+human_sec(<TMPL_VAR VolRetention>),
+human_sec(<TMPL_VAR VolUseDuration>),
+"<TMPL_VAR MaxVolJobs>",
+"<TMPL_VAR MaxVolFiles>",
+human_size(<TMPL_VAR MaxVolBytes>),
+"<TMPL_VAR VolNum>",
+img,
+img2,
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6),
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/lang/es/tpl/end.tpl b/gui/bweb/lang/es/tpl/end.tpl
new file mode 100644 (file)
index 0000000..072a52b
--- /dev/null
@@ -0,0 +1,5 @@
+</div>
+<div style="float: right;"></div>
+</div>
+</body>
+</html>
diff --git a/gui/bweb/lang/es/tpl/error.tpl b/gui/bweb/lang/es/tpl/error.tpl
new file mode 100644 (file)
index 0000000..56ea697
--- /dev/null
@@ -0,0 +1,4 @@
+<h1>Un error ha ocurrido :</h1>
+<pre>
+<TMPL_VAR NAME=error>
+</pre>
diff --git a/gui/bweb/lang/es/tpl/fileset_view.tpl b/gui/bweb/lang/es/tpl/fileset_view.tpl
new file mode 100644 (file)
index 0000000..17d666b
--- /dev/null
@@ -0,0 +1,20 @@
+ <div class='titlediv'>
+  <h1 class='newstitle'> 
+   FileSet <TMPL_VAR fileset>
+  </h1>
+ </div>
+ <div class='bodydiv'>
+
+ <img src="/bweb/add.png" alt="included"> Incluido :
+ <pre>
+<TMPL_LOOP I><TMPL_VAR file>
+</TMPL_LOOP></pre>
+
+ <img src="/bweb/remove.png" alt="excluded"> Excluido :
+ <pre>
+<TMPL_LOOP E><TMPL_VAR file>
+</TMPL_LOOP></pre>
+
+Nota: Cuidado, este es el fileset actual, puede haber cambiado...
+
+ </div>
diff --git a/gui/bweb/lang/es/tpl/fv_file_attribs.tpl b/gui/bweb/lang/es/tpl/fv_file_attribs.tpl
new file mode 100644 (file)
index 0000000..613c854
--- /dev/null
@@ -0,0 +1,12 @@
+<div class='titlediv'>
+  <h1 class='newstitle'> Información acerca <TMPL_VAR filename> </h1>
+</div>
+<div class='bodydiv'>
+   <table>
+    <tr><td>size : </td> <td> <TMPL_VAR size>  </td></tr>
+    <tr><td>ctime :</td> <td> <TMPL_VAR atime> </td></tr>
+    <tr><td>mtime :</td> <td> <TMPL_VAR mtime> </td></tr>
+    <tr><td>atime :</td> <td> <TMPL_VAR atime> </td></tr>
+    <tr><td>md5 :  </td> <td> <TMPL_VAR md5>   </td></tr>
+   </table>
+</div>
diff --git a/gui/bweb/lang/es/tpl/general.tpl b/gui/bweb/lang/es/tpl/general.tpl
new file mode 100644 (file)
index 0000000..f8da969
--- /dev/null
@@ -0,0 +1,30 @@
+
+<script type="text/javascript" language="JavaScript">
+bweb_add_refresh();
+</script>
+<div class='titlediv'>
+  <h1 class="newstitle">
+   Informaciones
+  </h1>
+</div>
+<div class="bodydiv">
+  <table>
+   <tr><td>Cantidad Clientes:</td>  <td> <TMPL_VAR nb_client> </td>
+       <td>Bytes Almacenados:</td> <td> <TMPL_VAR nb_bytes> </td>
+       <td>Cantidad Medios:</td>        <td> <TMPL_VAR nb_media> </td>
+   </tr>
+   <tr><td>Tamaño Base de Datos:</td>      <td> <TMPL_VAR db_size> </td>
+       <td>Cantidad Pools:</td>         <td> <TMPL_VAR nb_pool> </td>
+       <td>Cantidad Jobs:</td>         <td> <TMPL_VAR nb_job> </td>
+   </tr>
+   <tr><td>Jobs fallados (<TMPL_VAR label>):</td> 
+       
+<td <TMPL_IF nb_err> class='joberr' </TMPL_IF>>
+   <TMPL_VAR nb_err> 
+</td>
+       <td></td>         <td></td>
+       <td></td>         <td></td>
+   </tr>
+  
+  </table>
+</div>
diff --git a/gui/bweb/lang/es/tpl/graph.tpl b/gui/bweb/lang/es/tpl/graph.tpl
new file mode 100644 (file)
index 0000000..7683901
--- /dev/null
@@ -0,0 +1,172 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'>Estadísticas</h1>
+ </div>
+ <div class='bodydiv'>
+<table border='0'>
+<td>
+<form name='form1' action='?' method='GET'>
+        <div class="otherboxtitle">
+          Options &nbsp;
+        </div>
+        <div class="otherbox">
+<table border='0'>
+<tr>
+  <td valign='top'>
+    <h2>Nivel</h2>
+    <select name='level' class='formulaire'>
+      <option id='level_Any' value='Any'>Cualquiera</option>
+      <option id='level_F' value='F'>Completo</option>
+      <option id='level_D' value='D'>Diferencial</option>
+      <option id='level_I' value='I'>Incremental</option>
+    </select>     
+  </td><td valign='top'>
+    <h2>Estado</h2>
+    <select name='status' class='formulaire'>
+      <option id='status_Any' value='Any'>Cualquiera</option>
+      <option id='status_T'   value='T'>Ok</option>
+      <option id='status_f'   value='f'>Error</option>
+      <option id='status_A'   value='A'>Cancelado</option>
+    </select>   
+  </td>
+</tr>
+<tr>
+  <td valign='top'>
+    <h2>Tiempo</h2>
+    <select name='age' class='formulaire'>
+      <option id='age_604800'   value='604800'>Esta Semana</option>
+      <option id='age_2678400'  value='2678400'>Últimos 30 días</option>
+      <option id='age_15552000' value='15552000'>Últimos 6 meses</option>
+    </select>     
+  </td>
+  <td  valign='top'>
+    <h2>Tamaño</h2>
+     Ancho: &nbsp;<input class='formulaire' type='text' 
+                         name='width' value='<TMPL_VAR width>' size='4'><br/>
+     Alto:  <input type='text' class='formulaire' 
+                name='height' value='<TMPL_VAR height>' size='4'><br/>
+  </td>
+</tr>
+<tr>
+  <td valign='top'> 
+    <h2>Clients</h2>
+    <select name='client' size='15' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_clients>
+      <option id='client_<TMPL_VAR clientname>'><TMPL_VAR clientname></option>
+</TMPL_LOOP>
+    </select>
+  </td>
+  <td valign='top'> 
+    <h2>Nombre Job</h2>
+    <select name='jobname' size='15' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_jobnames>
+      <option><TMPL_VAR NAME=jobname></option>
+</TMPL_LOOP>
+    </select>
+  </td>
+</tr>
+<tr>
+  <td> <h2> Tipo </h2> 
+ <select name='graph' class='formulaire'>
+   <option id='job_size'     value='job_size' title="Job size per job for the period">Tamaño Job</option>
+   <option id='job_duration' value='job_duration' title="Job duration per job for the period">Duración Job</option>
+   <option id='job_rate' value='job_rate' title="Job rate per job for the period">Velocidad Job</option>
+   <option id='job_file' value='job_file' title="Number of backed files per job for the period">Archivos Job</option>
+   <option id='job_count_phour' value='job_count_phour' title="Number of jobs per hour for the period">Job por hora</option>
+   <option id='job_count_pday' value='job_count_pday' title="Number of jobs per day for the period">Job por dia</option>
+   <option id='job_avg_phour' value='job_avg_pday' title="Average backup size per day for the period">Job avg B/hour</option>
+   <option id='job_avg_pday' value='job_avg_pday' title="Average backup size per hour for the period">Job avg B/day</option>
+   <option id='job_sum_phour' value='job_sum_phour' title="Job size per hour">Job total B/hour</option>
+   <option id='job_sum_pday' value='job_sum_pday' title="Job size per day">Job total B/day</option>
+   <option id='job_count_hour' value='job_count_hour' title="Number of jobs per hour for the period">Jobs Count (h)</option>
+   <option id='job_count_day' value='job_count_day' title="Number of jobs per day for the period">Jobs Count (d)</option>
+   <option id='job_avg_hour' value='job_avg_hour' title="Average backup size per hour for the period">Job avg size (h)</option>
+   <option id='job_avg_day' value='job_avg_day' title="Average backup size per day for the period">Job avg size (d)</option>
+   <option id='job_sum_hour' value='job_sum_hour' title="Job size per hour for the period">Job Bytes (h)</option>
+   <option id='job_sum_day' value='job_sum_day' title="Job size per day for the period">Job Bytes (d)</option>
+ </select>
+  </td>
+  <td valign='bottom'> 
+    <h2>Número de items</h2>
+    <input type='text' name='limit' value='<TMPL_VAR NAME=limit>' 
+        class='formulaire' size='4'>
+  </td>
+</tr>
+<tr>
+<td><h2> Tipo de Gráfico </h2> 
+  <select name='gtype' class='formulaire'>
+    <option id='gtype_bars' value='bars'>Barras</option>
+<!--  <option id='gtype_bars3d' value='bars3d'>Barras3d</option> -->
+    <option id='gtype_lines' value='lines'>Líneas</option>
+    <option id='gtype_linespoints' value='linespoints'>Líneas y puntos</option>
+</td>
+<td>
+  <input type='hidden' name='action' value='graph'>
+  <input type='submit' name='_action' value='graficar' class='formulaire'> 
+</td>
+</tr>
+</table>
+        </div>
+
+</form>
+</td>
+<td>
+
+ <div class="otherboxtitle">
+ Current &nbsp;
+ </div>
+ <div class="otherbox">
+ <img src='bgraph.pl?<TMPL_VAR NAME=url>' alt='Nothing to display, Try a bigger date range'>
+ </div>
+
+</td>
+</table>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+  <TMPL_LOOP qclients>
+     document.getElementById('client_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+  <TMPL_IF status>
+     document.getElementById('status_<TMPL_VAR status>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF level>
+     document.getElementById('level_<TMPL_VAR level>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF age>
+     document.getElementById('age_<TMPL_VAR age>').selected=true;
+  </TMPL_IF>
+
+<TMPL_IF qfilesets>
+  for (var i=0; i < document.form1.fileset.length; ++i) {
+  <TMPL_LOOP qfilesets>
+     if (document.form1.fileset[i].value == <TMPL_VAR name>) {
+        document.form1.fileset[i].selected = true;
+     }
+  </TMPL_LOOP>
+  }
+</TMPL_IF>
+
+<TMPL_IF qjobnames>
+  for (var i=0; i < document.form1.jobname.length; ++i) {
+  <TMPL_LOOP qjobnames>
+     if (document.form1.jobname[i].value == <TMPL_VAR name>) {
+        document.form1.jobname[i].selected = true;
+     }
+  </TMPL_LOOP>
+  }
+</TMPL_IF>
+
+  <TMPL_IF graph>
+     document.getElementById('<TMPL_VAR graph>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF gtype>
+     document.getElementById('gtype_<TMPL_VAR gtype>').selected=true;
+  </TMPL_IF>
+
+</script>
diff --git a/gui/bweb/lang/es/tpl/help_extern.tpl b/gui/bweb/lang/es/tpl/help_extern.tpl
new file mode 100644 (file)
index 0000000..d46cdaa
--- /dev/null
@@ -0,0 +1,45 @@
+<br/>
+<div class='titlediv'>
+ <h1 class='newstitle'> Ayuda para expulsar medios (part 1/2)</h1>
+</div>
+<div class='bodydiv'>
+Se seleccionará el mejor candidato para expulsar. Se le pedirá
+realizar su selección en la próxima pantalla.
+  <form action="?" method='GET'>
+   <table>
+    <tr><td>Pool:</td>      
+        <td><select name='pool' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_pools>
+             <option><TMPL_VAR NAME=name></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td>Tipo Medio:</td>      
+        <td><select name='mediatype' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_mediatypes>
+             <option><TMPL_VAR NAME=mediatype></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td> Ubicación : </td>
+        <td><select name='location' class='formulaire'>
+  <TMPL_LOOP NAME=db_locations>
+      <option id='loc_<TMPL_VAR NAME=location>' value='<TMPL_VAR NAME=location>'><TMPL_VAR NAME=location></option>
+  </TMPL_LOOP>
+    </select>
+        </td>
+    </tr>
+    <tr>
+        <td>Número de medio <br/> a expulsar:</td> 
+        <td> <input type='text' name='limit' size='3' class='formulaire' 
+              value='10'> </td>
+    </tr>
+    <tr>
+        <td><input type="image" name='action' value='compute_extern_media' title='Siguiente' src='/bweb/next.png'>
+        </td><td/>
+    </tr>
+   </table>
+   </form>
+</div>
diff --git a/gui/bweb/lang/es/tpl/help_extern_compute.tpl b/gui/bweb/lang/es/tpl/help_extern_compute.tpl
new file mode 100644 (file)
index 0000000..ac1a3db
--- /dev/null
@@ -0,0 +1,67 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Ayuda para expulsar medios (part 2/2)</h1>
+ </div>
+ <div class='bodydiv'>
+  Ahora puede verificar la selección y expulsar el medio.
+   <form action='?' method='get'>
+    <table id='compute'></table>
+    <table><tr>
+    <td style='align: left;'>
+    <input type="image" onclick='javascript:window.history.go(-2);' title='Volver' src='/bweb/prev.png'>
+    </td><td style='align: right;'>
+    <input type="image" name='action' value='extern' src='/bweb/extern.png' title='Expulsar selección'>
+   </td></tr>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Nombre Volumen","Estado Volumen",
+                       "Tipo Medio","Nombre Pool","Fecha Escritura", 
+                       "Expiración", "Selección");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP NAME=Medias>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.value = '<TMPL_VAR NAME=volumename>';
+chkbox.name  = 'media';
+chkbox.checked = 'on';
+
+data.push( new Array(
+"<TMPL_VAR NAME=volumename>",
+"<TMPL_VAR NAME=volstatus>",
+"<TMPL_VAR NAME=mediatype>",
+"<TMPL_VAR NAME=name>",
+"<TMPL_VAR NAME=lastwritten>",
+"<TMPL_VAR NAME=expire>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "compute",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6)
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/lang/es/tpl/help_intern.tpl b/gui/bweb/lang/es/tpl/help_intern.tpl
new file mode 100644 (file)
index 0000000..314764c
--- /dev/null
@@ -0,0 +1,52 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Ayuda para cargar medios (part 1/2)</h1>
+</div>
+<div class="bodydiv">
+Se seleccionará el mejor candidato para cargar. Se le pedirá
+realizar su selección en la próxima pantalla.
+  <form action="?" method='GET'>
+   <table>
+    <tr><td>Pool:</td>      
+        <td><select name='pool' class='formulaire' multiple>
+<TMPL_LOOP db_pools>
+             <option><TMPL_VAR name></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td>Tipo Medio:</td>      
+        <td><select name='mediatype' class='formulaire' multiple>
+<TMPL_LOOP db_mediatypes>
+             <option><TMPL_VAR mediatype></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td>
+    Ubicación : 
+    </td><td><select name='location' class='formulaire'>
+  <TMPL_LOOP db_locations>
+      <option value='<TMPL_VAR location>'><TMPL_VAR location></option>
+  </TMPL_LOOP>
+    </select>
+    </td>
+    </tr>
+    <tr>
+        <td>Expiración :</td> 
+        <td> <input type='checkbox' name='expired' class='formulaire' 
+                checked> </td>
+    </tr>
+    <tr>
+        <td>Número de medio <br/> a cargar:</td> 
+        <td> <input type='text' name='limit' class='formulaire' 
+                size='3' value='10'> </td>
+    </tr>
+    <tr>
+        <td><input type="image" name='action' value='compute_intern_media' 
+                title='Siguiente' src='/bweb/next.png'>
+        </td><td/>
+    </tr>
+   </table>
+   </form>
+</div>
diff --git a/gui/bweb/lang/es/tpl/help_intern_compute.tpl b/gui/bweb/lang/es/tpl/help_intern_compute.tpl
new file mode 100644 (file)
index 0000000..8a8cd5c
--- /dev/null
@@ -0,0 +1,67 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Ayuda para cargar medios (part 2/2)</h1>
+ </div>
+ <div class='bodydiv'>
+  Ahora puede verificar la selección y cargar el medio
+   <form action='?' method='get'>
+    <table id='compute'></table>
+    <table><tr>
+    <td style='align: left;'>
+    <input type="image" onclick='javascript:window.history.go(-2);' title='Volver' src='/bweb/prev.png'>
+    </td><td style='align: right;'>
+    <input type="image" name='action' value='move_media' title='Cargar selección' src='/bweb/intern.png'>
+   </td></tr>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Nombre Volumen","Estado Volumen",
+                       "Tipo de Medio","Nombre Pool","Fecha Escritura", 
+                       "Expiración", "Selección");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP NAME=Medias>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.name = 'media';
+chkbox.value= '<TMPL_VAR NAME=volumename>';
+chkbox.checked = 'on';
+
+data.push( new Array(
+"<TMPL_VAR NAME=volumename>",
+"<TMPL_VAR NAME=volstatus>",
+"<TMPL_VAR NAME=mediatype>",
+"<TMPL_VAR NAME=name>",
+"<TMPL_VAR NAME=lastwritten>",
+"<TMPL_VAR NAME=expire>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "compute",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6)
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/lang/es/tpl/install.tpl b/gui/bweb/lang/es/tpl/install.tpl
new file mode 100644 (file)
index 0000000..749c5d2
--- /dev/null
@@ -0,0 +1,9 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Install notes </h1>
+</div>
+<div class='bodydiv'>
+
+
+
+</div>
diff --git a/gui/bweb/lang/es/tpl/location_add.tpl b/gui/bweb/lang/es/tpl/location_add.tpl
new file mode 100644 (file)
index 0000000..7b5ab20
--- /dev/null
@@ -0,0 +1,28 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Nueva Ubicación </h1>
+</div>
+<div class='bodydiv'>
+   <form action="?" method='get'>
+    <table>
+     <tr><td>Ubicación :</td>     
+         <td> 
+          <input class="formulaire" type='text' value='' size='32' name='location'> 
+         </td>
+     </tr>
+     <tr><td>Cost :</td> 
+         <td> <input class="formulaire" type='text' value='10' name='cost' size='3'>
+         </td>
+     </tr>
+     <tr><td>Activado :</td> 
+         <td> <input class="formulaire" type='checkbox' value='10' name='enabled'>
+         </td>
+     </tr>
+    </table>
+    <input type="image" name='action' value='location_add' title="save"
+      src='/bweb/save.png'>
+   </form>
+
+Tips: It's a good idea to have a location per autochanger. 
+
+</div>
diff --git a/gui/bweb/lang/es/tpl/location_edit.tpl b/gui/bweb/lang/es/tpl/location_edit.tpl
new file mode 100644 (file)
index 0000000..11856be
--- /dev/null
@@ -0,0 +1,26 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Ubicación : <TMPL_VAR Location></h1>
+</div>
+<div class='bodydiv'>
+   <form action="?" method='get'>
+    <input type='hidden' name='location' value='<TMPL_VAR location>'>
+    <table>
+     <tr><td>Ubicación :</td>     
+         <td> 
+          <input class="formulaire" type='text' value='<TMPL_VAR location>' size='32' name='newlocation'> 
+         </td>
+     </tr>
+     <tr><td>Cost :</td> 
+         <td> <input class="formulaire" type='text' value='<TMPL_VAR cost>' name='cost' size='3'>
+         </td>
+     </tr>
+     <tr><td>Activado :</td> 
+         <td> <input class="formulaire" type='checkbox' name='enabled' <TMPL_IF enabled> checked </TMPL_IF> >
+         </td>
+     </tr>
+    </table>
+    <input type="image" name='action' value='location_save'
+     src='/bweb/save.png'>
+   </form>
+</div>
diff --git a/gui/bweb/lang/es/tpl/move_media.tpl b/gui/bweb/lang/es/tpl/move_media.tpl
new file mode 100644 (file)
index 0000000..797d766
--- /dev/null
@@ -0,0 +1,85 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'>Mover Medio</h1>
+ </div>
+ <div class="bodydiv">
+   <form action='?' method='get'>
+    <table id='id<TMPL_VAR NAME=ID>'></table>
+    <table border='0'>
+    <tr><td> Nueva Ubicación: </td><td>
+<select name='newlocation' class='formulaire'>
+    <TMPL_LOOP NAME=db_locations>
+    <option value='<TMPL_VAR NAME=location>'><TMPL_VAR NAME=location></option>
+    </TMPL_LOOP>
+</select>
+    </td></tr><tr><td> Estado: </td><td>
+<select name='volstatus' class='formulaire'>
+    <option value=''>No Actualizar</option>
+    <option value='Append'>Listo</option>
+    <option value='Archive'>Archivado</option>
+    <option value='Disabled'>Desactivado</option>
+    <option value='Cleaning'>Limpieza</option>
+    <option value='Error'>Error</option>
+    <option value='Full'>Lleno</option>
+    <option value='Purged'>Purgado</option>
+    <option value='Read-Only'>ectura</option>
+    <option value='Recycle'>Reciclado</option>
+    <option value='Used'>Usado</option>
+</select>
+    </td><tr><td> Usuario: </td><td>
+<input type='text' name='user' value='<TMPL_VAR loginname>' class='formulaire'>
+    </td></tr>
+    </td></tr><tr><td> Comentario: </td><td>
+<textarea name="comment" class='formulaire'></textarea>
+    </td></tr>
+    </table>
+    <label>
+    <input type="image" type='submit' name='action' value='change_location' src='/bweb/apply.png'> Mover
+    </label>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Nombre Volumen", "Ubicación", "Selección");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP NAME=medias>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.value = '<TMPL_VAR name=volumename>';
+chkbox.name  = 'media';
+chkbox.checked = 1;
+
+data.push( new Array(
+"<TMPL_VAR NAME=volumename>",
+"<TMPL_VAR NAME=location>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR NAME=ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6),
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/lang/es/tpl/run_job.tpl b/gui/bweb/lang/es/tpl/run_job.tpl
new file mode 100644 (file)
index 0000000..f0692e4
--- /dev/null
@@ -0,0 +1,33 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Jobs Definidos: </h1>
+ </div>
+ <div class='bodydiv'>
+  <form name='form1' action='?' method='GET'>  
+  <table border='0'>
+
+   <tr><td>Nombre Job: </td><td>
+   <select name='job'>
+    <TMPL_LOOP jobs>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+   </td></tr>
+   </table>
+   <br/>
+   <label>
+   <input type="image" name='action' value='enable_job' title='Activar'
+    src='/bweb/inflag1.png'> Activado
+   </label>
+   <label>
+   <input type="image" name='action' value='disable_job' title='Desactivar'
+    src='/bweb/inflag0.png'> Desactivado
+   </label>
+   <label>
+   <input type="image" name='action' value='run_job_mod' title='Ejecutar Ahora'
+    src='/bweb/R.png'> Ejecutar Ahora
+   </label>
+  </form>
+ </div>
diff --git a/gui/bweb/lang/es/tpl/run_job_mod.tpl b/gui/bweb/lang/es/tpl/run_job_mod.tpl
new file mode 100644 (file)
index 0000000..0229122
--- /dev/null
@@ -0,0 +1,138 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Ejecutar Job : <TMPL_VAR job> on <TMPL_VAR client></h1>
+ </div>
+ <div class='bodydiv'>
+  <form name='form1' action='?' method='GET'>  
+  <table border='0'>
+
+   <tr><td>Nombre del Job: </td><td>
+   <select name='job'>
+    <TMPL_LOOP jobs>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+   </td></tr><tr><td>Pool: </td><td>
+
+   <select name='pool'>        
+     <option value=''></option>
+    <TMPL_LOOP pools>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+   </td></tr><tr><td>Cliente: </td><td>
+
+   <select name='client'>
+    <TMPL_LOOP clients>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+
+   </td></tr><tr><td>FileSet: </td><td>
+   <select name='fileset'>
+    <TMPL_LOOP filesets>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+
+   </td></tr><tr><td>Almacenamiento: </td><td>
+   <select name='storage'>
+    <TMPL_LOOP storages>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+
+   </td></tr><tr><td>Nivel: </td><td>
+   <select name='level'>
+     <option id='level_Incremental' value='Incremental'>Incremental</option>
+     <option id='level_Full' value='Full'>Completo</option>
+     <option id='level_Differential' value='Differential'>Diferencial</option>
+   </select>
+
+   </td></tr><tr id='more1' style="visibility:hidden"><td>Hora Inicio: </td><td>
+   <input class='formulaire' 
+         type='text' title='YYYY-MM-DD HH:MM:SS'
+          size='17' name='when' value='<TMPL_VAR when>'>
+
+   </td></tr><tr id='more2' style="visibility:hidden"><td>Prioridad: </td><td>
+   <input class='formulaire' type='text' 
+          size='3' name='priority' value='<TMPL_VAR priority>'>
+
+   </td></tr>
+   </table>
+   <br/>
+  <label onclick='
+           document.getElementById("more1").style.visibility="visible";
+           document.getElementById("more2").style.visibility="visible";'>
+  <img title='Muestra más opciones' src='/bweb/add.png'>Más opciones</label>
+  <label>
+  <input type="image" name='action' value='run_job_now' title='Ejecutar job'
+   src='/bweb/R.png'>Ejecutar Ahora
+  </label>
+  <label>
+  <input type="image" name='action' value='fileset_view' title='Ver FileSet'
+   src='/bweb/zoom.png'>Ver FileSet
+  </label>
+  </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+  <TMPL_IF job>
+     ok=1;
+     for(var i=0; ok && i < document.form1.job.length; i++) {
+       if (document.form1.job[i].value == '<TMPL_VAR job>') {
+           document.form1.job[i].selected=true;
+           ok=0;
+       }
+     }
+  </TMPL_IF>
+  <TMPL_IF client>
+     ok=1;
+     for(var i=0; ok && i < document.form1.client.length; i++) {
+       if (document.form1.client[i].value == '<TMPL_VAR client>') {
+           document.form1.client[i].selected=true;
+           ok=0;
+       }
+     }
+  </TMPL_IF>
+  <TMPL_IF pool>
+     ok=1;
+     for(var i=0; ok && i < document.form1.pool.length; i++) {
+       if (document.form1.pool[i].value == '<TMPL_VAR pool>') {
+           document.form1.pool[i].selected=true;
+           ok=0;
+       }
+     }
+  </TMPL_IF>
+  <TMPL_IF storage>
+     ok=1;
+     for(var i=0; ok && i < document.form1.storage.length; i++) {
+       if (document.form1.storage[i].value == '<TMPL_VAR storage>') {
+           document.form1.storage[i].selected=true;
+           ok=0;
+       }
+     }
+  </TMPL_IF>
+  <TMPL_IF level>
+<!--     document.getElementById('level_<TMPL_VAR level>').selected=true; -->
+  </TMPL_IF>
+  <TMPL_IF fileset>
+     ok=1;
+     for(var i=0; ok && i < document.form1.fileset.length; i++) {
+       if (document.form1.fileset[i].value == '<TMPL_VAR fileset>') {
+           document.form1.fileset[i].selected=true;
+           ok=0;
+       }
+     }
+  </TMPL_IF>
+</script>
diff --git a/gui/bweb/lang/es/tpl/running_job.tpl b/gui/bweb/lang/es/tpl/running_job.tpl
new file mode 100644 (file)
index 0000000..7acda4e
--- /dev/null
@@ -0,0 +1,96 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Jobs en Ejecución </h1>
+ </div>
+ <div class='bodydiv'>
+   <form action='?' method='GET'>
+   <table id='id<TMPL_VAR NAME=ID>'></table>
+   <br/>
+<label>
+<input type='image' name='action' value='dsp_cur_job' 
+ title='Ver job' src='/bweb/zoom.png'>
+</label>
+<label>
+<input type="image" type='submit' name='action' value='cancel_job'
+ onclick="return confirm('Esta seguro que quiere cancelar el Job?')"
+ title='Cancelar job' src='/bweb/cancel.png'>
+</label>
+   </form>
+
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+var header = new Array("JobId",
+                       "Cliente",
+                       "Nombre Job", 
+                       "Nivel",
+                       "Inicio", 
+                       "Duración", 
+//                       "Archivos Job",
+//                       "Bytes Job", 
+                       "Estado",
+                       "Selección"
+        );
+
+var data = new Array();
+var chkbox;
+var img;
+
+<TMPL_LOOP NAME=Jobs>
+a = document.createElement('A');
+a.href='?action=dsp_cur_job;jobid=<TMPL_VAR JobId>';
+
+img = document.createElement("IMG");
+img.src = '/bweb/<TMPL_VAR NAME=JobStatus>.png';
+img.title = jobstatus['<TMPL_VAR NAME=JobStatus>'];
+
+a.appendChild(img);
+
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'radio';
+chkbox.name = 'jobid';
+chkbox.value = '<TMPL_VAR NAME=jobid>';
+
+data.push( new Array(
+"<TMPL_VAR NAME=JobId>",
+"<TMPL_VAR NAME=ClientName>",     
+"<TMPL_VAR NAME=JobName>",    
+joblevel['<TMPL_VAR NAME=Level>'],      
+"<TMPL_VAR NAME=StartTime>",
+"<TMPL_VAR NAME=duration>",
+//"<TMPL_VAR NAME=JobFiles>",   
+//"<TMPL_VAR NAME=JobBytes>",
+a,
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR NAME=ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: true,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+// disable_sorting: new Array(6)
+ padding: 3
+}
+);
+
+// get newest backup first
+nrsTables['id<TMPL_VAR NAME=ID>'].fieldSort(0);
+
+bweb_add_refresh();
+
+</script>
diff --git a/gui/bweb/lang/es/tpl/scheduled_job.tpl b/gui/bweb/lang/es/tpl/scheduled_job.tpl
new file mode 100644 (file)
index 0000000..4b23904
--- /dev/null
@@ -0,0 +1,71 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Próximos Jobs </h1>
+ </div>
+ <div class='bodydiv'>
+    <form action='?' method='GET'>
+     <table id='id<TMPL_VAR ID>'></table>
+     <label>
+     <input type="image" name='action' value='run_job_mod'
+      src='/bweb/R.png' title='Ejecutar Ahora'>  Ejecutar Ahora
+     </label>
+     <label>
+      <input type="image" name='action' value='disable_job'
+       src='/bweb/inflag0.png' title='Desactivar'> Desactivar
+      </label>
+    </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Programado",
+                       "Nivel",
+                      "Tipo",
+                      "Prioridad", 
+                       "Nombre",
+                       "Volumen",
+                      "Selección");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP list>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'radio';
+chkbox.name = 'job';
+chkbox.value = '<TMPL_VAR name>';
+
+data.push( new Array(
+"<TMPL_VAR date>",    
+"<TMPL_VAR level>",
+"<TMPL_VAR type>",     
+"<TMPL_VAR priority>",    
+"<TMPL_VAR name>",      
+"<TMPL_VAR volume>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: true,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+// disable_sorting: new Array(6),
+ padding: 3
+}
+);
+</script>
diff --git a/gui/bweb/lang/es/tpl/stats.tpl b/gui/bweb/lang/es/tpl/stats.tpl
new file mode 100644 (file)
index 0000000..a3bd1ce
--- /dev/null
@@ -0,0 +1,9 @@
+<div class='titlediv'>
+  <h1 class='newstitle'> Estadísticas </h1>
+</div>
+<div class='bodydiv'>
+<a href='?action=job;age=172800;jobtype=B'>
+<img width='450' height='200' src='bgraph.pl?age=2678400;width=450;height=200;graph=job_sum_day;limit=500;action=graph;legend=off' alt='Nothing to display'>
+</a>
+</div>
+
diff --git a/gui/bweb/lang/es/tpl/update_location.tpl b/gui/bweb/lang/es/tpl/update_location.tpl
new file mode 100644 (file)
index 0000000..11b4335
--- /dev/null
@@ -0,0 +1,65 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'>Actualizar Ubicación del Medio</h1>
+ </div> 
+ <div class="bodydiv">
+   <form action='?' method='get'>
+    <table id='id<TMPL_VAR NAME=ID>'></table>
+    New location : <select class='formulaire' name='newlocation'>
+   <TMPL_LOOP NAME=db_locations>
+      <option id='loc_<TMPL_VAR NAME=location>' value='<TMPL_VAR NAME=location>'><TMPL_VAR NAME=location></option>
+   </TMPL_LOOP>
+  </select>
+  <input type="image" name='action' value='save_location' src='/bweb/apply.png'>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Nombre del Volumen", "Ubicación", "Selección");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP NAME=medias>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.value = '<TMPL_VAR name=volumename>';
+chkbox.name  = 'media';
+chkbox.checked = 1;
+
+data.push( new Array(
+"<TMPL_VAR NAME=volumename>",
+"<TMPL_VAR NAME=location>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR NAME=ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6)
+ rows_per_page: rows_per_page
+}
+);
+
+<TMPL_IF qnewlocation>
+ document.getElementById('loc_' + <TMPL_VAR qnewlocation>).selected=true;
+</TMPL_IF>
+
+</script>
diff --git a/gui/bweb/lang/es/tpl/update_media.tpl b/gui/bweb/lang/es/tpl/update_media.tpl
new file mode 100644 (file)
index 0000000..e9f41be
--- /dev/null
@@ -0,0 +1,159 @@
+<br/>
+<div class='titlediv'>
+ <h1 class='newstitle'> Actualizar Medio <TMPL_VAR volumename></h1>
+</div>
+<div class='bodydiv'>
+  <form name='form1' action="?" method='GET'>
+   <table>
+    <tr><td>Nombre del Volumen:</td>
+        <td><input type='text' name='media' class='formulaire' value='<TMPL_VAR volumename>' title='Change this to update an other media'>
+        </td>
+    </tr>
+    <tr><td>Pool:</td>
+        <td><select name='pool' class='formulaire'>
+<TMPL_LOOP db_pools>
+             <option value='<TMPL_VAR name>'><TMPL_VAR name></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td>Estado:</td>
+        <td><select name='volstatus' class='formulaire'>
+           <option value='Append'>Listo</option>
+           <option value='Archive'>Archivado</option>
+           <option value='Disabled'>Desactivado</option>
+           <option value='Cleaning'>Limpieza</option>
+           <option value='Error'>Error</option>
+          <option value='Full'>Lleno</option>
+           <option value='Read-Only'>Lectura</option>
+           <option value='Used'>Usado</option>
+           </select>
+        </td>
+    </tr>
+
+    <tr><td>Slot:</td>
+        <td> 
+          <input class='formulaire' type='text' 
+                 name='slot' value='<TMPL_VAR slot>'>
+        </td>
+    </tr>
+
+    <tr><td>Cargado:</td>
+        <td> 
+          <input class='formulaire' type='checkbox' 
+               name='inchanger' <TMPL_IF inchanger>checked</TMPL_IF>>
+        </td>
+    </tr>
+
+    <tr><td> Ubicación : </td>
+        <td><select name='location' class='formulaire'>
+        <option value=''></option>
+  <TMPL_LOOP db_locations>
+      <option value='<TMPL_VAR location>'><TMPL_VAR location></option>
+  </TMPL_LOOP>
+    </select>
+        </td>
+    </tr>
+    <tr><td> Período de Retención: </td>
+        <td>
+          <input class='formulaire' type='text' title='ex: 3 days, 1 month'
+               name='volretention' value='<TMPL_VAR volretention>'>
+        </td>
+    </tr>
+    <tr><td> Use duration: </td>
+        <td>
+          <input class='formulaire' type='text' title='ex: 3 days, 1 month'
+               name='voluseduration' value='<TMPL_VAR voluseduration>'>
+        </td>
+    </tr>
+    <tr><td> Jobs Máximos: </td>
+        <td>
+          <input class='formulaire' type='text' title='ex: 10'
+               name='maxvoljobs' value='<TMPL_VAR maxvoljobs>'>
+        </td>
+    </tr>
+    <tr><td> Archivos Máximos: </td>
+        <td>
+          <input class='formulaire' type='text' title='ex: 10000'
+               name='maxvolfiles' value='<TMPL_VAR maxvolfiles>'>
+        </td>
+    </tr>
+    <tr><td> Bytes Máximos: </td>
+        <td>
+          <input class='formulaire' type='text' title='ex: 10M, 11G'
+               name='maxvolbytes' value='<TMPL_VAR maxvolbytes>'>
+        </td>
+    </tr>
+    <tr><td>Recycle Pool:</td>
+        <td><select name='poolrecycle' class='formulaire'>
+<TMPL_LOOP db_pools>
+             <option value='<TMPL_VAR name>'><TMPL_VAR name></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td> Comentario: </td>
+        <td>
+          <input class='formulaire' type='text' title='a comment'
+               name='comment' value='<TMPL_VAR comment>'>
+        </td>
+    </tr>
+
+    </table>
+<table>
+ <td>
+ <label>
+  <input type="image" name='action' value='do_update_media' src='/bweb/apply.png'> Apply
+  </label>
+  <label>
+  <input type="image" name='action' title='Update from pool'
+    value='update_from_pool' src='/bweb/update.png'> Actualizar del Pool
+  </label>
+ </form>
+ </td>
+ <td>
+  <form action='?' method='GET'>
+   <input type='hidden' name='pool' value='<TMPL_VAR poolname>'>
+   <label>
+    <input type="image" name='action' value='media'
+     src='/bweb/zoom.png'> Ver Pool
+   </label>
+  </form>
+ </td>
+</table>
+</div>
+
+<script type="text/javascript" language='JavaScript'>
+var ok=1;
+for (var i=0; ok && i < document.form1.pool.length; ++i) {
+   if (document.form1.pool[i].value == '<TMPL_VAR poolname>') {
+      document.form1.pool[i].selected = true;
+      ok=0;
+   }
+}
+
+ok=1;
+for (var i=0; ok && i < document.form1.pool.length; ++i) {
+   if (document.form1.poolrecycle[i].value == '<TMPL_VAR poolrecycle>') {
+      document.form1.poolrecycle[i].selected = true;
+      ok=0;
+   }
+}
+
+ok=1;
+for (var i=0; ok && i < document.form1.location.length; ++i) {
+   if (document.form1.location[i].value == '<TMPL_VAR location>') {
+      document.form1.location[i].selected = true;
+      ok=0;
+   }
+}
+
+ok=1;
+for (var i=0; ok && i < document.form1.volstatus.length; ++i) {
+   if (document.form1.volstatus[i].value == '<TMPL_VAR volstatus>') {
+      document.form1.volstatus[i].selected = true;
+      ok=0;
+   }
+}
+
+</script>
diff --git a/gui/bweb/lang/fr/tpl/about.tpl b/gui/bweb/lang/fr/tpl/about.tpl
new file mode 100644 (file)
index 0000000..49106b7
--- /dev/null
@@ -0,0 +1,39 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> A propos </h1>
+</div>
+<div class='bodydiv'>
+<pre>
+   Bweb - A Bacula web interface
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+
+   The main author of Bweb is Eric Bollengier.
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation plus additions
+   that are listed in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
+   Switzerland, email:ftf@fsfeurope.org.
+
+   nrsTable Copyright 2005 New Roads School (GPL)
+   kaiska css Copyright Willy Morin (BWL)
+</pre>
+</div>
diff --git a/gui/bweb/lang/fr/tpl/ach_add.tpl b/gui/bweb/lang/fr/tpl/ach_add.tpl
new file mode 100644 (file)
index 0000000..c9d90b3
--- /dev/null
@@ -0,0 +1,71 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'><TMPL_UNLESS name>Nouvelle</TMPL_UNLESS> Robotique (Autochanger) </h1>
+</div>
+<div class='bodydiv'>
+   Vous devez créer une Location du même nom que votre robotique.<br/><br/>
+   <form name='form1' action="?" method='get'>
+    <table>
+     <tr><td>Nom :</td>     
+         <td>
+          <select name='ach' class='formulaire' id='ach'>
+<TMPL_LOOP devices><option value='<TMPL_VAR name>'><TMPL_VAR name></option></TMPL_LOOP>
+          </select>
+         </td>
+     </tr>
+     <tr><td>Pre-commande :</td> 
+         <td> <input class="formulaire" type='text' id='precmd' value='sudo'
+           title='peut Ãªtre "sudo" ou "ssh storage@storagehost"...' name='precmd'>
+         </td>
+     </tr>
+     <tr><td>commande mtx :</td> 
+         <td> <input class="formulaire" type='text' name='mtxcmd' size='32'
+               value='/usr/sbin/mtx' id='mtxcmd'>
+         </td>
+     </tr>
+     <tr><td>Périphérique :</td> 
+         <td> <input class="formulaire" type='text' name='device' 
+               value='/dev/changer' id='device'>
+         </td>
+     </tr>
+    <tr><td><b>Lecteurs</b></td><td/></tr>
+    <TMPL_LOOP devices>
+    <tr>
+     <td><input class='formulaire' type='checkbox' id='drive_<TMPL_VAR name>'
+                name='drives' value='<TMPL_VAR name>'><TMPL_VAR name>
+     </td>
+     <td>index <input type='text' title='drive index' class='formulaire'
+               id='index_<TMPL_VAR name>' value='' 
+                name='index_<TMPL_VAR name>' size='3'>
+     </td>
+    </tr>
+    </TMPL_LOOP>
+    </table>
+    <input type="image" name='action' value='ach_add' src='/bweb/save.png'>
+   </form>
+</div>
+
+<script type="text/javascript" language="JavaScript">
+  <TMPL_IF name>
+  for (var i=0; i < document.form1.ach.length; ++i) {
+     if (document.form1.ach[i].value == '<TMPL_VAR name>') {
+        document.form1.ach[i].selected = true;
+     }
+  }
+  </TMPL_IF>
+  <TMPL_IF mtxcmd>
+     document.getElementById('mtxcmd').value='<TMPL_VAR mtxcmd>';
+  </TMPL_IF>
+  <TMPL_IF precmd>
+     document.getElementById('precmd').value='<TMPL_VAR precmd>';
+  </TMPL_IF>
+  <TMPL_IF device>
+     document.getElementById('device').value='<TMPL_VAR device>';
+  </TMPL_IF>
+  <TMPL_IF drives>
+   <TMPL_LOOP drives>
+     document.getElementById('drive_<TMPL_VAR name>').checked=true;
+     document.getElementById('index_<TMPL_VAR name>').value=<TMPL_VAR index>;
+   </TMPL_LOOP>
+  </TMPL_IF>
+</script>
diff --git a/gui/bweb/lang/fr/tpl/ach_content.tpl b/gui/bweb/lang/fr/tpl/ach_content.tpl
new file mode 100644 (file)
index 0000000..4a1cfda
--- /dev/null
@@ -0,0 +1,161 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> 
+Robotique : <TMPL_VAR Name> (<TMPL_VAR nb_drive> Lecteurs
+<TMPL_IF nb_io><TMPL_VAR nb_io> IMPORT/EXPORT</TMPL_IF>)</h1>
+ </div>
+ <div class='bodydiv'>
+   <form action='?' method='get'>
+    <input type='hidden' name='ach' value='<TMPL_VAR name>'>
+    <TMPL_IF "Update">
+    <font color='red'> Vous devez lancer la mise Ã  jour des slots, le contenu de la robotique est différent de ce qui est indiqué dans la base de bacula. </font>
+    <br/>
+    </TMPL_IF>
+    <table border='0'>
+    <tr>
+    <td valign='top'>
+    <div class='otherboxtitle'>
+     Options
+    </div>
+    <div class='otherbox'>
+<label>
+<input type="image" name='action' value='label_barcodes'
+        title='Labélisation des médias, (label barcodes)' src='/bweb/label.png'>Labéliser
+</label>
+<TMPL_IF nb_io>
+<label>
+<input type="image" name='action' value='eject'
+        title='Mettre les médias sélectionnés dans le guichet' src='/bweb/extern.png'>
+Ejecter
+</label>
+<label>
+<input type="image" name='action' value='clear_io'
+        title='Vider le guichet' src='/bweb/intern.png'>
+Vider le guichet
+</label>
+</TMPL_IF>
+<label>
+<input type="image" name='action' value='update_slots'
+        title='Mettre Ã  jour la base bacula, (update slots)' src='/bweb/update.png'>
+Scanner
+</label>
+<br/><br/>
+<label>
+<input type="image" name='action' value='ach_load'
+       title='Charger un lecteur' src='/bweb/load.png'>
+Mount
+</label>
+<label>
+<input type="image" name='action' value='ach_unload'
+       title='Décharger un lecteur' src='/bweb/unload.png'>
+Umount
+</label>
+
+   </div>
+    <td width='200'/>
+    <td>
+    <b> Lecteurs : </b><br/>
+    <table id='id_drive'></table> <br/>
+    </td>
+    </tr>
+    </table>
+    <b> Contenu : </b><br/>
+    <table id='id_ach'></table>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Slot réel", "Slot", "Nom de volume","Taille","Statut",
+                      "Type","Pool","Dernière Ã©criture", 
+                       "Expiration", "Sélection");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP Slots>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.name = 'slot';
+chkbox.value = '<TMPL_VAR realslot>';
+
+data.push( new Array(
+"<TMPL_VAR realslot>",
+"<TMPL_VAR slot>",
+"<TMPL_VAR volumename>",
+human_size(<TMPL_VAR volbytes>),
+"<TMPL_VAR volstatus>",
+"<TMPL_VAR mediatype>",
+"<TMPL_VAR name>",
+"<TMPL_VAR lastwritten>",
+"<TMPL_VAR expire>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id_ach",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+// page_nav: true,
+// rows_per_page: rows_per_page,
+// disable_sorting: new Array(5,6)
+ padding: 3
+}
+);
+
+var header = new Array("Index", "Nom du lecteur", "Nom de volume", "Sélection");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP Drives>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.name = 'drive';
+chkbox.value = '<TMPL_VAR index>';
+
+data.push( new Array(
+"<TMPL_VAR index>",
+"<TMPL_VAR name>",
+"<TMPL_VAR load>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id_drive",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+// page_nav: true,
+// rows_per_page: rows_per_page,
+// disable_sorting: new Array(5,6),
+ padding: 3
+}
+);
+
+</script>
diff --git a/gui/bweb/lang/fr/tpl/begin.tpl b/gui/bweb/lang/fr/tpl/begin.tpl
new file mode 100644 (file)
index 0000000..b604b28
--- /dev/null
@@ -0,0 +1,66 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+<head>
+<title>Bweb - Interface Web de Bacula</title>
+<link rel="SHORTCUT ICON" href="/bweb/favicon.ico">
+<script type="text/javascript" language="JavaScript" src="/bweb/natcompare.js"></script>
+<script type="text/javascript" language="JavaScript" src="/bweb/nrs_table.js"></script>
+<script type="text/javascript" language="JavaScript" src="/bweb/bweb.js"></script>
+<link type="text/css" rel="stylesheet" href="/bweb/style.css"/>
+<link type="text/css" rel="stylesheet" href="/bweb/kaiska.css"/>
+<link type="text/css" rel="stylesheet" href="/bweb/bweb.css"/>
+</head>
+<body>
+
+<script type="text/javascript" language="JavaScript">
+if (navigator.appName == 'Konqueror') {
+       alert("Désolé, bweb fonctionne seulement avec mozilla.");
+}
+</script>
+
+<ul id="menu">
+ <li><a href="bweb.pl?">Accueil</a> </li>
+ <li><a href="bweb.pl?action=client">Clients</a></li>
+ <li><a href="bweb.pl?action=run_job">Jobs</a>
+   <ul> 
+     <li><a href="bweb.pl?action=run_job">Jobs définis</a>
+     <li><a href="bweb.pl?action=job">Historique</a> </li>
+     <li><a href="bweb.pl?action=running">Jobs en cours</a>
+     <li><a href="bweb.pl?action=next_job">Prochains Jobs</a> </li>
+     <li><a href="bweb.pl?action=restore" title="Lancer brestore">Restauration</a> </li>
+   </ul>
+ </li>
+ <li style="padding: 0.25em 2em;">Medias
+  <ul>
+     <li><a href="bweb.pl?action=pool">Pools</a> </li>
+     <li><a href="bweb.pl?action=location">Localisations</a> </li>
+     <li><a href="bweb.pl?action=media">Tous les Medias</a><hr></li>
+     <li><a href="bweb.pl?action=extern_media">Externaliser</a> </li>
+     <li><a href="bweb.pl?action=intern_media">Internaliser</a> </li>
+  </ul>
+ </li>
+<TMPL_IF achs>
+ <li style="padding: 0.25em 2em;">Robotiques
+  <ul>
+<TMPL_LOOP achs>
+   <li><a href="bweb.pl?action=ach_view;ach=<TMPL_VAR name>"><TMPL_VAR name></a></li>
+</TMPL_LOOP>
+  </ul>
+ </li>
+</TMPL_IF> 
+ <li><a href="bweb.pl?action=graph"> Statistiques </a></li>
+ <li> <a href="bweb.pl?action=view_conf"> Configuration </a> </li>
+ <li> <a href="bweb.pl?action=about"> A propos </a> </li>
+ <li style="padding: 0.25em 2em;float: right;">&nbsp;Logged as <TMPL_VAR NAME=loginname> </li>
+ <li style="float: right;white-space: nowrap;">
+<input type="image" class="button" title="chercher un media" onclick="search_media();" src="/bweb/tape.png"><input type="image" title="chercher un client" onclick="search_client();" src="/bweb/client.png">&nbsp;<input class='formulaire' style="margin: 0 2px 0 2px; padding: 0 0 0 0;" id='searchbox' type='text' size='8' value="rechercher..." onclick="this.value='';" title="chercher un media ou un client"></li>
+</ul>
+
+<form name="search" action="bweb.pl?" method='GET'>
+ <input type="hidden" name="action" value="">
+ <input type="hidden" name="re_media" value="">
+ <input type="hidden" name="re_client" value="">
+</form>
+
+<div style="clear: left;">
+<div style="float: left;">
diff --git a/gui/bweb/lang/fr/tpl/change_location.tpl b/gui/bweb/lang/fr/tpl/change_location.tpl
new file mode 100644 (file)
index 0000000..18c77cb
--- /dev/null
@@ -0,0 +1,38 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> 
+   Déplacer des médias
+  </h1>
+ </div>
+ <div class='bodydiv'>
+
+<form action="?" method='GET'>
+<table>
+<tr>
+<td><b>To: </b></td><td><input class='formulaire' name='email' value='<TMPL_VAR email>'></td>
+</tr><tr>
+<td><b>Subject: </b></td><td><input class='formulaire' name='subject' value='[BACULA] Deplacement des medias vers <TMPL_VAR newlocation>' size='80'></td>
+</tr><tr>
+<td></td>
+<td>
+<textarea name='content' class='formulaire' cols='80' rows='32'>
+Bonjour,
+
+Pouvez vous déplacer ces médias vers <TMPL_VAR newlocation> ?
+Média :
+<TMPL_LOOP Medias>
+ - <TMPL_VAR VolumeName>  (<TMPL_VAR location>)
+</TMPL_LOOP>
+
+Quand cela sera terminé, pouvez vouscliquer sur le lien ci-dessous pour mettre Ã  jour la localisation ?
+(Vous pouvez utiliser ce lien : <TMPL_VAR url>).
+
+Merci
+</textarea>
+</td></tr></table>
+<input type="hidden" name='action' value='move_email'>
+<input class='formulaire' type='submit' name='bp' value='Envoyer'>
+</form>
+<br>
+<a href="<TMPL_VAR url>"><img alt='update now' src='/bweb/update.png'>Mettre Ã  jour maintenant</a>
+</div>
diff --git a/gui/bweb/lang/fr/tpl/client_job_status.tpl b/gui/bweb/lang/fr/tpl/client_job_status.tpl
new file mode 100644 (file)
index 0000000..1269b46
--- /dev/null
@@ -0,0 +1,39 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> 
+       Job <TMPL_VAR JobName> en cours sur <TMPL_VAR Client>
+  </h1>
+ </div>
+ <div class='bodydiv'>
+
+<table>
+ <tr>
+  <td> <b> Nom du job : </b> <td> <td> <TMPL_VAR jobname> (<TMPL_VAR jobid>) <td> 
+ </tr>
+ <tr>
+  <td> <b> Fichier en cours : </b> <td> <td> <TMPL_VAR "processing file"> </td>
+ </tr>
+ <tr>
+  <td> <b> Vitesse : </b> <td> <td> <TMPL_VAR "bytes/sec"> B/s</td>
+ </tr>
+ <tr>
+  <td> <b> Fichiers vus : </b> <td> <td> <TMPL_VAR "files examined"></td>
+ </tr>
+ <tr>
+  <td> <b> Taille : </b> <td> <td> <TMPL_VAR bytes></td>
+ </tr>
+</table>
+<form name='form1' action='?' method='GET'>
+<input type="image" name='action' value='dsp_cur_job' 
+ src='/bweb/update.png' title='refresh'>&nbsp;
+<input type='hidden' name='client' value='<TMPL_VAR Client>'>
+<input type='hidden' name='jobid' value='<TMPL_VAR JobId>'>
+<input type="image" name='action' value='cancel_job'
+       onclick="return confirm('Vous voulez annuler ce job ?')"
+        title='Annuler ce job' src='/bweb/cancel.png'>&nbsp;
+</form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+  bweb_add_refresh();
+</script>
diff --git a/gui/bweb/lang/fr/tpl/client_list.tpl b/gui/bweb/lang/fr/tpl/client_list.tpl
new file mode 100644 (file)
index 0000000..614dfad
--- /dev/null
@@ -0,0 +1,70 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Clients</h1>
+ </div>
+ <div class='bodydiv'>
+<form action='?' method='GET'>
+     <table id='id<TMPL_VAR NAME=ID>'></table>
+       <div class="otherboxtitle">
+          Actions &nbsp;
+        </div>
+        <div class="otherbox">
+<!--        <h1>Actions</h1> -->       
+       <label>
+       <input type="image" name='action' value='job' title="Voir l'historique" src='/bweb/zoom.png'>Historique</label> &nbsp;
+       <label>
+       <input type="image" name='action' value='dsp_cur_job' title='Voir les jobs courants' src='/bweb/zoom.png'>Jobs courants</label> &nbsp;
+       <label>
+       <input type="image" name='action' value='client_status' title='Statut' src='/bweb/zoom.png'>Statut</label> &nbsp;
+       <label>
+       <input type="image" name='action' value='client_stats' title='Statistiques' src='/bweb/chart.png'>Statistiques</h1></label> &nbsp;
+       </label>
+        </div>
+
+</form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+var header = new Array("Nom", "Sélection", "Description", "Purge automatique", "Rétention des fichiers", "Rétention des jobs");
+
+var data = new Array();
+var chkbox ;
+
+<TMPL_LOOP NAME=Clients>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.name = 'client';
+chkbox.value = '<TMPL_VAR NAME=Name>';
+
+data.push( 
+  new Array( "<TMPL_VAR NAME=Name>", 
+             chkbox,
+            "<TMPL_VAR NAME=Uname>",
+            "<TMPL_VAR NAME=AutoPrune>",
+            human_sec(<TMPL_VAR NAME=FileRetention>),
+            human_sec(<TMPL_VAR NAME=JobRetention>)
+              )
+) ; 
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR NAME=ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+ disable_sorting: new Array(1)
+}
+);
+</script>
diff --git a/gui/bweb/lang/fr/tpl/command.tpl b/gui/bweb/lang/fr/tpl/command.tpl
new file mode 100644 (file)
index 0000000..ce9a906
--- /dev/null
@@ -0,0 +1,9 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> <TMPL_VAR title> : <TMPL_VAR name></h1>
+ </div>
+ <div class='bodydiv'>
+  <pre id='log' style='font-size: 10px'>
+<TMPL_VAR content>
+  </pre>
+ </div>
diff --git a/gui/bweb/lang/fr/tpl/config_edit.tpl b/gui/bweb/lang/fr/tpl/config_edit.tpl
new file mode 100644 (file)
index 0000000..9bdea5d
--- /dev/null
@@ -0,0 +1,50 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Configuration </h1>
+</div>
+<div class='bodydiv'>
+   <form action="?" method='post'>
+    <table>
+     <tr>  <td><b>Connexion SQL</b></td>  <td/></tr>
+     <tr><td>DBI :</td>     
+         <td> 
+          <input class="formulaire" type='text' value='<TMPL_VAR NAME=dbi>' size='64' name='dbi'> 
+         </td>
+     </tr>
+     <tr><td>user :</td> 
+         <td> <input class="formulaire" type='text' value='<TMPL_VAR NAME=user>' name='user'>
+         </td>
+     </tr>
+     <tr><td>password :</td> 
+         <td> <input class="formulaire" type='password' value='<TMPL_VAR NAME=password>' name='password'> 
+         </td></tr>
+
+     <tr>  <td><b>Options Générales</b></td>  <td/></tr>
+
+     <tr><td>email_media :</td> 
+         <td> <input class="formulaire" type='text' value='<TMPL_VAR NAME=email_media>' name='email_media'> 
+         </td></tr>
+         </td></tr>
+
+     <tr>  <td><b>Configuration Bweb</b></td>  <td/></tr>
+
+     <tr><td>graph_font :</td> 
+         <td> <input class="formulaire" title="/chemin/vers/une/font.ttf" type='text' value='<TMPL_VAR NAME=graph_font>' size='64' name='graph_font'> 
+         </td></tr>
+     <tr><td>template_dir :</td> 
+         <td> <input class="formulaire" title="/chemin/vers/votre/template_dir" type='text' value='<TMPL_VAR NAME=template_dir>' size='64' name='template_dir'> 
+         </td></tr>
+     <tr><td>fv_write_path :</td> 
+         <td> <input class="formulaire" title="Ce répertoire doit Ãªtre accessible en Ã©criture pour apache et Ãªtre sous /bweb/fv" type='text' value='<TMPL_VAR fv_write_path>' size='64' name='fv_write_path'> 
+         </td></tr>
+     <tr><td>bconsole :</td> 
+         <td> <input class="formulaire" title="/chemin/vers/bconsole -n -c /chemin/vers/bconsole.conf" type='text' value='<TMPL_VAR NAME=bconsole>' size='64' name='bconsole'> 
+         </td></tr>
+     <tr><td>debug :</td> 
+         <td> <input class="formulaire" type='checkbox' name='debug' <TMPL_IF debug> checked='checked' value='on' </TMPL_IF> > 
+         </td></tr>
+    </table>
+    <input type="image" name='action' value='apply_conf' src='/bweb/save.png'>
+   </form>
+</div>
diff --git a/gui/bweb/lang/fr/tpl/config_view.tpl b/gui/bweb/lang/fr/tpl/config_view.tpl
new file mode 100644 (file)
index 0000000..a028858
--- /dev/null
@@ -0,0 +1,62 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Configuration </h1>
+</div>
+<div class='bodydiv'>
+   <table>
+    <tr>  <td><b>Connexion SQL</b></td>  <td/></tr>
+    <tr><td>DBI :</td>      <td> <TMPL_VAR dbi>      </td></tr>
+    <tr><td>user :</td>     <td> <TMPL_VAR user>     </td></tr>
+    <tr><td>password :</td> <td> xxxxxxxx </td></tr>
+    <tr>  <td><b>Options Générales</b></td>  <td/></tr>
+    <tr><td>email_media :</td> <td> <TMPL_VAR email_media> </td></tr>
+    <tr>  <td><b>Configuration Bweb</b></td>  <td/></tr>
+    <tr><td>config_file :</td> <td> <TMPL_VAR config_file> </td></tr>
+    <tr><td title="/chemin/vers/votre/template_dir">template_dir :</td> <td> <TMPL_VAR template_dir> </td></tr>
+    <tr><td title="/chemin/vers/une/font.ttf">graph_font :</td> <td> <TMPL_VAR graph_font> </td></tr>
+    <tr><td title="Ce répertoire doit Ãªtre accessible en ecriture pour apache et Ãªtre sous /bweb/fv">fv_write_path :</td> <td> <TMPL_VAR fv_write_path> </td></tr>
+    <tr><td title="/chemin/vers/bconsole -n -c /chemin/vers/bconsole.conf">bconsole :</td> <td> <TMPL_VAR bconsole> </td></tr>
+    <tr><td>debug :</td> <td> <TMPL_VAR debug> </td></tr>
+    <TMPL_IF achs>
+    <tr>  <td><b>Robotique (Autochanger)</b></td>  <td/></tr>
+    <tr>
+     <td>
+     <form action='?' method='GET'>
+     <table border='0'>
+    <TMPL_LOOP achs>
+      <tr> 
+       <td>
+<label>
+ <input type='radio' name='ach' value='<TMPL_VAR name>'><TMPL_VAR name>
+</label>
+       </td>
+      </tr>
+    </TMPL_LOOP>
+    </table>
+   <td>
+  
+   <input type="image" name="action" value="ach_edit" title="modifier" src='/bweb/edit.png'> 
+   <input type="image" name='action' value='ach_del' title='supprimer' src='/bweb/remove.png'>
+   <input type='image' name='action' value='ach_view' title='voir' src='/bweb/zoom.png'>
+    </form>
+    </td>
+   </tr>
+   </TMPL_IF achs>
+   <tr>
+   <td><hr></td><td></td>
+   </tr>
+  </table>
+
+  <form action='?' method='GET'>
+   <label>
+   <input name='action' value='edit_conf' type="image" title='Modifier' src='/bweb/edit.png'> Modifier
+   </label>
+   <label>
+   <input name='action' value='ach_add' type="image" title='Ajouter une robotique' src='/bweb/add.png'> Ajouter une robotique
+   </label>
+  </form>
+
+  <TMPL_IF error>
+  info :  <TMPL_VAR error> </br>
+  </TMPL_IF>
+</div>
diff --git a/gui/bweb/lang/fr/tpl/display_client_job.tpl b/gui/bweb/lang/fr/tpl/display_client_job.tpl
new file mode 100644 (file)
index 0000000..0440f55
--- /dev/null
@@ -0,0 +1,65 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Historique de <TMPL_VAR clientname> (<TMPL_VAR Filter>)
+  </h1>
+ </div>
+ <div class='bodydiv'>
+
+   <table id='id<TMPL_VAR ID>'></table>
+
+<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_size;status=T">
+    <img src="/bweb/chart.png" alt="taille des sauvegardes" title="évolution de la taille des sauvegardes"/>
+    </a>
+<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_duration;status=T">
+    <img src="/bweb/chart.png" alt="durée des sauvegardes" title="évolution de la durée des sauvegardes"/>
+    </a>
+<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_rate;status=T">
+    <img src="/bweb/chart.png" alt="vitesse des sauvegardes" title="évolution de la vitesse des sauvegardes"/>
+    </a>                               
+ </div>
+
+
+<script type="text/javascript" language="JavaScript">
+var header = new Array("JobId", "Nom du Job", "File Set", "Niveau", "Début", 
+                  "Nb fichiers", "Taille", "Erreurs");
+
+var data = new Array();
+
+<TMPL_LOOP Jobs>
+data.push( new Array(
+"<TMPL_VAR JobId>",
+"<TMPL_VAR JobName>",    
+"<TMPL_VAR FileSet>",
+"<TMPL_VAR Level>",
+"<TMPL_VAR StartTime>",
+"<TMPL_VAR JobFiles>",   
+human_size(<TMPL_VAR JobBytes>),
+"<TMPL_VAR JobErrors>"   
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: true,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+ disable_sorting: new Array(5,6)
+}
+);
+
+// get newest job first
+nrsTables['id<TMPL_VAR ID>'].fieldSort(0);
+</script>
diff --git a/gui/bweb/lang/fr/tpl/display_client_stats.tpl b/gui/bweb/lang/fr/tpl/display_client_stats.tpl
new file mode 100644 (file)
index 0000000..4cd2c14
--- /dev/null
@@ -0,0 +1,59 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Client : <TMPL_VAR NAME=clientname> (<TMPL_VAR NAME=label>)</h1>
+ </div>
+ <div class='bodydiv'>
+<form action='?'
+     <table id='id<TMPL_VAR NAME=ID>'></table>
+     <img src="bgraph.pl?client=<TMPL_VAR NAME=clientname>;graph=job_duration;age=2592000;width=420;height=200" alt='Données insufisantes' > &nbsp;
+     <img src="bgraph.pl?client=<TMPL_VAR NAME=clientname>;graph=job_rate;age=2592000;width=420;height=200" alt='Données insufisantes'> &nbsp;
+     <img src="bgraph.pl?client=<TMPL_VAR NAME=clientname>;graph=job_size;age=2592000;width=420;height=200" alt='Données insufisantes'> &nbsp;
+<!--   <div class="otherboxtitle">
+          Actions &nbsp;
+        </div>
+        <div class="otherbox">
+       <h1>Actions</h1> 
+       <input type="image" name='action' value='job' title="Voir l'historique"
+        src='/bweb/zoom.png'> &nbsp;
+       <input type="image" name='action' value='dsp_cur_job' title='Voir les job en cours' src='/bweb/zoom.png'> &nbsp;
+       <input type="image" name='action' value='client_stat' title='Statistiques' src='/bweb/zoom.png'> &nbsp;
+        </div>
+-->
+</form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+var header = new Array("Nom", "Nb Jobs", "Taille", "Nb Fichiers", "Nb Erreurs");
+
+var data = new Array();
+
+data.push( 
+  new Array( "<TMPL_VAR NAME=clientname>", 
+            "<TMPL_VAR NAME=nb_jobs>",
+            human_size(<TMPL_VAR NAME=nb_bytes>),
+            "<TMPL_VAR NAME=nb_files>",
+            "<TMPL_VAR NAME=nb_err>"
+             )
+) ; 
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR NAME=ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+// disable_sorting: new Array(1),
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/lang/fr/tpl/display_form_job.tpl b/gui/bweb/lang/fr/tpl/display_form_job.tpl
new file mode 100644 (file)
index 0000000..f205dd0
--- /dev/null
@@ -0,0 +1,126 @@
+<br/>
+<div class="otherboxtitle">
+  Filtre &nbsp;
+</div>
+<div class="otherbox">
+<form name='form1' action='?' method='GET'>
+<table border='0'>
+<tr>
+  <td valign='top'>
+    <h2>Niveau</h2>
+    <select name='level' class='formulaire'>
+      <option id='level_Any' value='Any'>Tous</option>
+      <option id='level_F' value='F'>Full</option>
+      <option id='level_D' value='D'>Différentielle</option>
+      <option id='level_I' value='I'>Incrémentale</option>
+    </select>     
+  </td>
+</tr>
+<tr>
+ <td valign='top'>
+    <h2>Statut</h2>
+    <select name='status' class='formulaire'>
+      <option id='status_Any' value='Any'>Tous</option>
+      <option id='status_T'   value='T'>Ok</option>
+      <option id='status_f'   value='f'>Erreur</option>
+      <option id='status_A'   value='A'>Annulé</option>
+    </select>     
+  </td>
+</tr>
+<tr>
+ <td valign='top'>
+    <h2>Pool</h2>
+    <select name='pool' class='formulaire'>
+      <option id='pool_tout' value=''>Tous</option>
+<TMPL_LOOP NAME=db_pools>
+      <option id='pool_<TMPL_VAR name>'><TMPL_VAR name></option>
+</TMPL_LOOP>
+    </select>
+  </td>
+</tr>
+<tr>
+  <td valign='top'>
+    <h2>Période</h2>
+    <select name='age' class='formulaire'>
+      <option id='age_604800'   value='604800'>Cette semaine</option>
+      <option id='age_2678400'  value='2678400'>30 derniers jours</option>
+      <option id='age_15552000' value='15552000'>6 derniers mois</option>
+    </select>     
+  </td>
+ </tr>
+ <tr>
+  <td valign='bottom'> 
+    <h2>Nombre d'élément</h2>
+    <input type='text' name='limit' value='<TMPL_VAR NAME=limit>' 
+       class='formulaire' size='4'>
+  </td>
+</tr>
+<tr>
+  <td valign='top'> 
+    <h2>Type</h2>
+    <select name='jobtype' class='formulaire'>
+      <option id='jobtype_any' value='all type'>Tous</option>
+      <option id='jobtype_B' value='B'>Backup</option>
+      <option id='jobtype_R' value='R'>Restauration</option>
+    </select>
+  </td>
+</tr>
+<tr>
+  <td valign='top'> 
+    <h2>Clients</h2>
+    <select name='client' size='15' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_clients>
+      <option id='client_<TMPL_VAR clientname>'><TMPL_VAR clientname></option>
+</TMPL_LOOP>
+    </select>
+  </td>
+</tr>
+<!--
+<tr>
+  <td valign='top'> 
+    <h2>File Set</h2>
+    <select name='fileset' size='15' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_filesets>
+      <option id='client_<TMPL_VAR fileset>'><TMPL_VAR NAME=fileset></option>
+</TMPL_LOOP>
+    </select>
+  </td>
+</tr>
+-->
+</table>
+  <input type="image" name='action' value='job' src='/bweb/update.png'>
+
+</form>
+</div>
+<script type="text/javascript" language="JavaScript">
+
+  <TMPL_LOOP qclients>
+     document.getElementById('client_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+  <TMPL_IF status>
+     document.getElementById('status_<TMPL_VAR status>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF level>
+     document.getElementById('level_<TMPL_VAR level>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF age>
+     document.getElementById('age_<TMPL_VAR age>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF jobtype>
+     document.getElementById('jobtype_<TMPL_VAR jobtype>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_LOOP qfilesets>
+     document.getElementById('fileset_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+  <TMPL_LOOP qpools>
+     document.getElementById('pool_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+</script>
+
diff --git a/gui/bweb/lang/fr/tpl/display_form_media.tpl b/gui/bweb/lang/fr/tpl/display_form_media.tpl
new file mode 100644 (file)
index 0000000..33d519e
--- /dev/null
@@ -0,0 +1,91 @@
+<div class="otherboxtitle">
+  Filtre &nbsp;
+</div>
+<div class="otherbox">
+<form name='form1' action='?' method='GET'>
+<table border='0'>
+<tr>
+  <td valign='top'>
+    <h2>Type de Média</h2>
+    <select name='mediatype' class='formulaire'>
+      <option id='mediatype_all' value=''></option>
+<TMPL_LOOP NAME=db_mediatypes>
+      <option id='mediatype_<TMPL_VAR mediatype>'><TMPL_VAR mediatype></option>
+</TMPL_LOOP>
+    </select>     
+  </td>
+</tr>
+<tr>
+  <td valign='top'>
+    <h2>Localisation</h2>
+    <select name='location' class='formulaire'>
+      <option id='location_all>' value=''></option>
+<TMPL_LOOP NAME=db_locations>
+      <option id='location_<TMPL_VAR location>'><TMPL_VAR location></option>
+</TMPL_LOOP>
+    </select>     
+  </td>
+</tr>
+<tr>
+ <td valign='top'>
+    <h2>Statut</h2>
+    <select name='volstatus' class='formulaire'>
+      <option id='volstatus_All' value=''></option>
+      <option id='volstatus_Append' value='Append'>Append</option>
+      <option id='volstatus_Full'   value='Full'>Full</option>
+      <option id='volstatus_Error'  value='Error'>Error</option>
+      <option id='volstatus_Used'   value='Used'>Used</option>
+      <option id='volstatus_Purged' value='Purged'>Purged</option>
+    </select>     
+  </td>
+</tr>
+<tr>
+ <td valign='top'>
+    <h2>Pool</h2>
+    <select name='pool' class='formulaire'>
+      <option id='pool_all>' value=''></option>
+<TMPL_LOOP NAME=db_pools>
+      <option id='pool_<TMPL_VAR name>'><TMPL_VAR name></option>
+</TMPL_LOOP>
+    </select>     
+  </td>
+</tr>
+ <tr>
+  <td valign='bottom'> 
+    <h2>Label</h2>
+    <input type='text' name='re_media' 
+      <TMPL_IF qre_media>value=<TMPL_VAR qre_media></TMPL_IF>
+       class='formulaire' size='8'>
+  </td>
+</tr>
+ <tr>
+  <td valign='bottom'> 
+    <h2>Nombre d'éléments</h2>
+    <input type='text' name='limit' value='<TMPL_VAR limit>' 
+       class='formulaire' size='4'>
+  </td>
+</tr>
+
+</table>
+  <input type="image" name='action' value='media' src='/bweb/update.png'>
+
+</form>
+</div>
+<script type="text/javascript" language="JavaScript">
+  <TMPL_IF volstatus>
+     document.getElementById('volstatus_<TMPL_VAR volstatus>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_LOOP qmediatypes>
+     document.getElementById('mediatype_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+  <TMPL_LOOP qpools>
+     document.getElementById('pool_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+  <TMPL_LOOP qlocations>
+     document.getElementById('location_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+</script>
+
diff --git a/gui/bweb/lang/fr/tpl/display_job.tpl b/gui/bweb/lang/fr/tpl/display_job.tpl
new file mode 100644 (file)
index 0000000..4006714
--- /dev/null
@@ -0,0 +1,81 @@
+ <div class='titlediv'>
+  <h1 class='newstitle'> Historique des Jobs (<TMPL_VAR Filter>)</h1>
+ </div>
+ <div class='bodydiv'>
+    <table id='id<TMPL_VAR ID>'></table>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+<TMPL_IF status>
+document.getElementById('status_<TMPL_VAR status>').checked = true;
+</TMPL_IF>
+
+
+
+var header = new Array("JobId",
+                      "Client",
+                      "Nom du Job", 
+                      "FileSet",
+//                     "Pool",
+                       "Niveau",
+                       "Début",
+                      "Durée",
+                       "Nb Fichier",
+                       "Taille", 
+                       "Erreurs",
+                      "Statut");
+
+var data = new Array();
+
+<TMPL_LOOP Jobs>
+a = document.createElement('A');
+a.href='?action=job_zoom;jobid=<TMPL_VAR JobId>';
+
+img = document.createElement("IMG");
+img.src=bweb_get_job_img("<TMPL_VAR JobStatus>", <TMPL_VAR joberrors>);
+img.title=jobstatus['<TMPL_VAR JobStatus>']; 
+
+a.appendChild(img);
+
+data.push( new Array(
+"<TMPL_VAR JobId>",
+"<TMPL_VAR Client>",     
+"<TMPL_VAR JobName>",    
+"<TMPL_VAR FileSet>",    
+//"<TMPL_VAR Pool>",
+"<TMPL_VAR Level>",      
+"<TMPL_VAR StartTime>",
+"<TMPL_VAR Duration>",
+"<TMPL_VAR JobFiles>",   
+human_size(<TMPL_VAR JobBytes>),
+"<TMPL_VAR joberrors>",   
+a
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: true,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+ disable_sorting: new Array(10),
+ padding: 3
+}
+);
+
+// get newest backup first
+nrsTables['id<TMPL_VAR ID>'].fieldSort(0);
+</script>
diff --git a/gui/bweb/lang/fr/tpl/display_job_zoom.tpl b/gui/bweb/lang/fr/tpl/display_job_zoom.tpl
new file mode 100644 (file)
index 0000000..1a21dd5
--- /dev/null
@@ -0,0 +1,131 @@
+ <div class='titlediv'>
+  <h1 class='newstitle'>Information sur un job</h1>
+ </div>
+ <div class="bodydiv">
+ <table id='id0'></table>
+ <table><td>
+ <form action='bweb.pl?'>
+  <input type='hidden' name='jobid' value='<TMPL_VAR jobid>'>
+  <label>
+  <input type="image" name='action' value='delete' title='Supprimer ce job'
+ onclick="return confirm('Voulez vous vraiment supprimer ce job du catalogue ?');"
+   src='/bweb/purge.png'> Purger
+  </label>
+ </form>
+ </td><td>
+ <form action='bweb.pl?'>
+  <TMPL_LOOP volumes>
+   <input type='hidden' name='media' value='<TMPL_VAR VolumeName>'>
+  </TMPL_LOOP>   
+  <label>
+  <input type="image" name='action' value='media' title='Voir les médias associés' 
+   src='/bweb/zoom.png'>Voir les médias
+  </label>
+ </form>
+ </td>
+ <td>
+ <form action='bweb.pl?'>
+  <input type='hidden' name='client' value='<TMPL_VAR Client>'>
+  <label>
+  <input type="image" name='action' value='job' title='Voir les jobs de <TMPL_VAR Client>' src='/bweb/zoom.png'>Voir les jobs
+  </label>
+ </form>
+ </td>
+ <td>
+ <form action='bweb.pl?'>
+  <input type='hidden' name='age' value='2678400'>
+  <input type='hidden' name='client' value='<TMPL_VAR Client>'>
+  <input type='hidden' name='jobname' value='<TMPL_VAR jobname>'>
+  <label>
+  <input type="image" name='action' value='graph' title='Voir les tendances'
+   src='/bweb/chart.png'> Voir les stats
+  </label>
+ </form>
+ </td>
+ <td>
+ <form action='bweb.pl?'>
+  <input type='hidden' name='fileset' value='<TMPL_VAR FileSet>'>
+  <label>
+  <input type="image" name='action' value='fileset_view' title='Voir le fileset associé'
+   src='/bweb/zoom.png'> Voir le FileSet
+  </label>
+ </form>
+ </td>
+<!-- Enlever ce commentaire pour activer le bfileview
+ <td>
+ <form action='bfileview.pl?'>
+  <input type='hidden' name='jobid' value='<TMPL_VAR jobid>'>
+  <input type='hidden' name='where' value='/'>
+  <label>
+  <input type="image" name='action' value='bfileview' 
+   title="Voir la répartition des fichiers"
+   onclick='if (<TMPL_VAR JobFiles> > 5000) { return confirm("Ce traitement peut prendre beaucoup de temps, voulez vous continuer ?")} else { return 1; }'
+   src='/bweb/colorscm.png'> Voir la répartition des fichiers
+  </label>
+ </form>
+ </td>
+-->
+ </table>
+</div>
+
+<script type="text/javascript" language='JavaScript'>
+var header = new Array("JobId",
+                      "Client",
+                      "Nom du Job", 
+                      "FileSet",
+                       "Niveau",
+                       "Début", 
+                      "Durée",
+                       "Fichiers",
+                       "Taille",
+                       "Erreurs",
+                      "Pool",
+                       "Volumes utilisés",
+                      "Statut");
+
+var data = new Array();
+
+img = document.createElement("IMG");
+img.src=bweb_get_job_img("<TMPL_VAR JobStatus>", <TMPL_VAR joberrors>);
+img.title=jobstatus['<TMPL_VAR JobStatus>']; 
+
+data.push( new Array(
+"<TMPL_VAR JobId>",
+"<TMPL_VAR Client>",     
+"<TMPL_VAR JobName>",    
+"<TMPL_VAR FileSet>",    
+"<TMPL_VAR Level>",      
+"<TMPL_VAR StartTime>",
+"<TMPL_VAR duration>",
+"<TMPL_VAR JobFiles>",   
+human_size(<TMPL_VAR JobBytes>),
+"<TMPL_VAR joberrors>",
+"<TMPL_VAR poolname>",
+"<TMPL_LOOP volumes><TMPL_VAR VolumeName>\n</TMPL_LOOP>",   
+img
+ )
+);
+
+nrsTable.setup(
+{
+ table_name:     "id0",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: true,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+// disable_sorting: new Array(6)
+ padding: 3
+}
+);
+
+</script>
diff --git a/gui/bweb/lang/fr/tpl/display_location.tpl b/gui/bweb/lang/fr/tpl/display_location.tpl
new file mode 100644 (file)
index 0000000..5637780
--- /dev/null
@@ -0,0 +1,66 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'>Localisation</h1>
+ </div>
+ <div class="bodydiv">
+   <form action='?' method='get'>
+    <table id='id<TMPL_VAR ID>'></table>
+    <input type="image" name='action' value='location_add' title='Ajouter' src='/bweb/add.png'>&nbsp;
+    <input type="image" name='action' value='location_del' title='Supprimer' src='/bweb/remove.png'>&nbsp;
+    <input type="image" name='action' value='location_edit' title='Modifier' src='/bweb/edit.png'>&nbsp;
+
+    <input type="image" name='action' value='media' title='Voir les médias'
+     src='/bweb/zoom.png'>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Nom","Enabled", "Coût", "Nb de volumes", "Sélection");
+
+var data = new Array();
+var chkbox;
+
+var img;
+
+<TMPL_LOOP Locations>
+img = document.createElement('IMG');
+img.src = '/bweb/inflag<TMPL_VAR enabled>.png';
+
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'radio';
+chkbox.name  = 'location';
+chkbox.value = '<TMPL_VAR Location>';
+
+data.push( new Array(
+"<TMPL_VAR Location>",
+img,
+"<TMPL_VAR Cost>",
+"<TMPL_VAR name=volnum>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6),
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/lang/fr/tpl/display_log.tpl b/gui/bweb/lang/fr/tpl/display_log.tpl
new file mode 100644 (file)
index 0000000..d093f58
--- /dev/null
@@ -0,0 +1,9 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Log : <TMPL_VAR name> sur <TMPL_VAR client> (<TMPL_VAR jobid>)</h1>
+ </div>
+ <div class='bodydiv'>
+  <pre id='log'>
+<TMPL_VAR lines>
+  </pre>
+ </div>
diff --git a/gui/bweb/lang/fr/tpl/display_media.tpl b/gui/bweb/lang/fr/tpl/display_media.tpl
new file mode 100644 (file)
index 0000000..9e4f8ec
--- /dev/null
@@ -0,0 +1,91 @@
+ <div class='titlediv'>
+  <h1 class='newstitle'> 
+   Médias
+  </h1>
+ </div>
+ <div class='bodydiv'>
+
+<TMPL_IF Pool>
+<h2>
+Pool : <a href="?action=pool;pool=<TMPL_VAR Pool>">
+         <TMPL_VAR Pool>
+       </a>
+</h2>
+</TMPL_IF>
+<TMPL_IF Location>
+<h2>
+Localisation : <TMPL_VAR location>
+</h2>
+</TMPL_IF>
+
+   <form action='?action=test' method='get'>
+    <table id='id_pool_<TMPL_VAR ID>'></table>
+      <input type="image" name='action' value='extern' title='Externaliser' src='/bweb/extern.png' onclick='return confirm("Voulez vous vraiment Ã©jecter les médias sélectionnés ?");'>&nbsp;
+      <input type="image" name='action' value='intern' title='Internaliser' src='/bweb/intern.png'>&nbsp;
+      <input type="image" name='action' value='update_media' title='Mettre Ã  jour' src='/bweb/edit.png'>&nbsp;
+      <input type="image" name='action' value='media_zoom' title='Informations' src='/bweb/zoom.png'>&nbsp;
+<!--
+      <input type="image" name='action' value='purge' title='Purger' src='/bweb/purge.png'>&nbsp;
+-->
+      <input type="image" name='action' value='prune' title='Prune' src='/bweb/prune.png'>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Nom du volume","En ligne","Taille", "Utilisation", "Statut",
+                      "Pool", "Type",
+                      "Dernière Ã©criture", "Expiration", "Sélection");
+
+var data = new Array();
+var img;
+var chkbox;
+var d;
+
+<TMPL_LOOP Medias>
+d = percent_usage(<TMPL_VAR volusage>);
+
+img = document.createElement('IMG');
+img.src = '/bweb/inflag<TMPL_VAR online>.png';
+
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.name = 'media';
+chkbox.value = '<TMPL_VAR volumename>';
+
+data.push( new Array(
+"<TMPL_VAR volumename>",
+img,
+human_size(<TMPL_VAR volbytes>),
+d,
+"<TMPL_VAR volstatus>",
+"<TMPL_VAR poolname>",
+"<TMPL_VAR mediatype>",
+"<TMPL_VAR lastwritten>",
+"<TMPL_VAR expire>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id_pool_<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+ rows_per_page: rows_per_page,
+ disable_sorting: new Array(1,3,9)
+}
+);
+</script>
diff --git a/gui/bweb/lang/fr/tpl/display_media_zoom.tpl b/gui/bweb/lang/fr/tpl/display_media_zoom.tpl
new file mode 100644 (file)
index 0000000..a73d7b3
--- /dev/null
@@ -0,0 +1,163 @@
+<table>
+<td valign='top'>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Media : <TMPL_VAR volumename> <TMPL_VAR comment></h1>
+ </div>
+ <div class='bodydiv'>
+    <b> Informations </b><br/>
+    <table id='id_info_<TMPL_VAR volumename>'></table>
+    <b> Statistiques </b><br/>
+    <table id='id_media_<TMPL_VAR volumename>'></table>
+    <b> Contenu </b></br>
+    <table id='id_jobs_<TMPL_VAR volumename>'></table>
+    <b> Actions </b></br>
+   <form action='?' method='get'>
+      <input type='hidden' name='media' value='<TMPL_VAR volumename>'>
+<TMPL_IF online>&nbsp;
+      <input type="image" name='action' value='extern' onclick='return confirm("Voulez vous vraiment Ã©jecter ce média ?");' title='Externaliser' src='/bweb/extern.png'>&nbsp;
+<TMPL_ELSE>
+      <input type="image" name='action' value='intern' title='Internaliser' src='/bweb/intern.png'>&nbsp;
+</TMPL_IF>
+      <input type="image" name='action' value='update_media' title='Mettre Ã  jour' src='/bweb/edit.png'>&nbsp;
+      <input type="image" name='action' value='purge' title='Purger' src='/bweb/purge.png' onclick="return confirm('Vous voulez vraiment purger ce volume ?')">&nbsp;
+      <input type="image" name='action' value='prune' title='Prune' src='/bweb/prune.png'>&nbsp;
+<TMPL_IF Locationlog>
+      <a href='#' onclick='document.getElementById("locationlog").style.visibility="visible";'><img title='Voir les déplacements' src='/bweb/zoom.png'></a>
+</TMPL_IF>
+   </form>
+ </div>
+</td>
+<td valign='top'style="visibility:hidden;" id='locationlog'>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Log sur les déplacements </h1>
+ </div>
+ <div class='bodydiv'>
+<pre>
+ <TMPL_VAR LocationLog>
+</pre>
+ </div>
+</td>
+</table>
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Pool","En ligne","Localisation","Statut", "Taille", "Expiration",
+                      "Rétention","Temps maxi d'utilisation", "Nb de job maxi" );
+
+var data = new Array();
+var img;
+
+img = document.createElement('IMG');
+img.src = '/bweb/inflag<TMPL_VAR online>.png';
+
+data.push( new Array(
+"<TMPL_VAR poolname>",
+img,
+"<TMPL_VAR location>",
+"<TMPL_VAR volstatus>",
+human_size(<TMPL_VAR nb_bytes>),
+"<TMPL_VAR expire>",
+human_sec(<TMPL_VAR volretention>),
+human_sec(<TMPL_VAR voluseduration>),
+"<TMPL_VAR maxvoljobs>"
+ )
+);
+
+nrsTable.setup(
+{
+ table_name:     "id_info_<TMPL_VAR volumename>",
+ table_header: header,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+ table_data: data,
+ header_color: header_color,
+ padding: 3,
+ disable_sorting: new Array(1)
+}
+);
+
+var header = new Array( "Nb montages", "Nb recyclages", "Temps de lecture", "Temps d'écriture", "Erreurs");
+
+var data = new Array();
+data.push( new Array(
+"<TMPL_VAR nb_mounts>",
+"<TMPL_VAR recyclecount>",
+human_sec(<TMPL_VAR volreadtime>),
+human_sec(<TMPL_VAR volwritetime>),
+"<TMPL_VAR nb_errors>"
+ )
+);
+
+nrsTable.setup(
+{
+ table_name:     "id_media_<TMPL_VAR volumename>",
+ table_header: header,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+ table_data: data,
+ header_color: header_color,
+// disable_sorting: new Array()
+ padding: 3
+}
+);
+
+
+var header = new Array("JobId","Nom","Début","Type",
+                      "Niveau", "Nb Fichiers", "Taille", "Statut");
+
+var data = new Array();
+var a;
+var img;
+
+<TMPL_LOOP jobs>
+a = document.createElement('A');
+a.href='?action=job_zoom;jobid=<TMPL_VAR JobId>';
+
+img = document.createElement("IMG");
+img.src="/bweb/<TMPL_VAR status>.png";
+img.title=jobstatus['<TMPL_VAR status>']; 
+
+a.appendChild(img);
+
+data.push( new Array(
+"<TMPL_VAR jobid>",
+"<TMPL_VAR name>",
+"<TMPL_VAR starttime>",
+"<TMPL_VAR type>",
+"<TMPL_VAR level>",
+"<TMPL_VAR files>",
+human_size(<TMPL_VAR bytes>),
+a
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id_jobs_<TMPL_VAR volumename>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6),
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/lang/fr/tpl/display_pool.tpl b/gui/bweb/lang/fr/tpl/display_pool.tpl
new file mode 100644 (file)
index 0000000..fc5c5e5
--- /dev/null
@@ -0,0 +1,88 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'>Pools de média</h1>
+ </div>
+ <div class="bodydiv">
+   <form action='?' method='get'>
+    <table id='id<TMPL_VAR ID>'></table>
+    <input type="image" type='submit' name='action' value='media' title='Afficher le contenu' src='/bweb/zoom.png'>
+<TMPL_LOOP MediaType>
+    <input type='hidden' name='mediatype' value=<TMPL_VAR name>>
+</TMPL_LOOP>
+   </form>
+   <br/>
+   Tips : Pour modifier les options d'un pool, vous devez Ã©diter la configuration bacula et
+   la recharger (reload). Après vous devez lancer "update pool=mypool" sur la bconsole.
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Nom","Recyclage","Rétention","Durée d'utilisation",
+                      "Nb job maxi par média","Nb fichier maxi par média", 
+                       "Taille maxi d'un média","Nb volumes", "Statut", "Utilisation", "Sélection");
+
+var data = new Array();
+var chkbox;
+var img;
+var img2;
+
+<TMPL_LOOP Pools>
+
+img = percent_display([
+<TMPL_IF nb_recycle>{ name: "Recycle", nb: <TMPL_VAR nb_recycle> },</TMPL_IF>
+<TMPL_IF nb_purged> { name: "Purged", nb: <TMPL_VAR nb_purged> },</TMPL_IF>
+<TMPL_IF nb_append> { name: "Append", nb: <TMPL_VAR nb_append> },</TMPL_IF>
+<TMPL_IF nb_full>   { name: "Full", nb: <TMPL_VAR nb_full> },    </TMPL_IF>
+<TMPL_IF nb_disabled>   { name: "Disabled", nb: <TMPL_VAR nb_disabled> },    </TMPL_IF>
+<TMPL_IF nb_error>  { name: "Error", nb: <TMPL_VAR nb_error> },  </TMPL_IF>
+<TMPL_IF nb_archive>{ name: "Archive", nb: <TMPL_VAR nb_archive> },</TMPL_IF>
+<TMPL_IF nb_used>   { name: "Used", nb: <TMPL_VAR nb_used> },    </TMPL_IF>
+<TMPL_IF NAME='nb_read-only'> { name: "Read-Only", nb: <TMPL_VAR NAME='nb_read-only'> }, </TMPL_IF>
+{}
+]);
+
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'radio';
+chkbox.value = '<TMPL_VAR Name>';
+chkbox.name  = 'pool';
+
+img2 = percent_usage(<TMPL_VAR poolusage>);
+
+data.push( new Array(
+"<TMPL_VAR Name>",
+"<TMPL_VAR Recycle>",
+human_sec(<TMPL_VAR VolRetention>),
+human_sec(<TMPL_VAR VolUseDuration>),
+"<TMPL_VAR MaxVolJobs>",
+"<TMPL_VAR MaxVolFiles>",
+human_size(<TMPL_VAR MaxVolBytes>),
+"<TMPL_VAR VolNum>",
+img,
+img2,
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6),
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/lang/fr/tpl/end.tpl b/gui/bweb/lang/fr/tpl/end.tpl
new file mode 100644 (file)
index 0000000..072a52b
--- /dev/null
@@ -0,0 +1,5 @@
+</div>
+<div style="float: right;"></div>
+</div>
+</body>
+</html>
diff --git a/gui/bweb/lang/fr/tpl/error.tpl b/gui/bweb/lang/fr/tpl/error.tpl
new file mode 100644 (file)
index 0000000..f14c4b4
--- /dev/null
@@ -0,0 +1,4 @@
+<h1>Une erreur s'est produite :</h1>
+<pre>
+<TMPL_VAR NAME=error>
+</pre>
diff --git a/gui/bweb/lang/fr/tpl/fileset_view.tpl b/gui/bweb/lang/fr/tpl/fileset_view.tpl
new file mode 100644 (file)
index 0000000..15b5081
--- /dev/null
@@ -0,0 +1,20 @@
+ <div class='titlediv'>
+  <h1 class='newstitle'> 
+   FileSet <TMPL_VAR fileset>
+  </h1>
+ </div>
+ <div class='bodydiv'>
+
+ <img src="/bweb/add.png" alt="included"> Ce qui est inclu :
+ <pre>
+<TMPL_LOOP I><TMPL_VAR file>
+</TMPL_LOOP></pre>
+
+ <img src="/bweb/remove.png" alt="excluded"> Ce qui est exclu :
+ <pre>
+<TMPL_LOOP E><TMPL_VAR file>
+</TMPL_LOOP></pre>
+
+Tips : Attention, ceci est le FileSet courant, sur une ancienne sauvegarde, il peut avoir changé.
+
+ </div>
diff --git a/gui/bweb/lang/fr/tpl/fv_file_attribs.tpl b/gui/bweb/lang/fr/tpl/fv_file_attribs.tpl
new file mode 100644 (file)
index 0000000..f40954a
--- /dev/null
@@ -0,0 +1,12 @@
+<div class='titlediv'>
+  <h1 class='newstitle'> Informations sur <TMPL_VAR filename> </h1>
+</div>
+<div class='bodydiv'>
+   <table>
+    <tr><td>taille : </td> <td> <TMPL_VAR size>  </td></tr>
+    <tr><td>ctime :  </td> <td> <TMPL_VAR atime> </td></tr>
+    <tr><td>mtime :  </td> <td> <TMPL_VAR mtime> </td></tr>
+    <tr><td>atime :  </td> <td> <TMPL_VAR atime> </td></tr>
+    <tr><td>md5 :    </td> <td> <TMPL_VAR md5>   </td></tr>
+   </table>
+</div>
diff --git a/gui/bweb/lang/fr/tpl/general.tpl b/gui/bweb/lang/fr/tpl/general.tpl
new file mode 100644 (file)
index 0000000..202bb95
--- /dev/null
@@ -0,0 +1,30 @@
+
+<script type="text/javascript" language="JavaScript">
+bweb_add_refresh();
+</script>
+<div class='titlediv'>
+  <h1 class="newstitle">
+   Informations
+  </h1>
+</div>
+<div class="bodydiv">
+  <table>
+   <tr><td>Nombre de clients :</td>      <td> <TMPL_VAR nb_client> </td>
+       <td>Total des sauvegardes :</td> <td> <TMPL_VAR nb_bytes> </td>
+       <td>Nombre de medias :</td>        <td> <TMPL_VAR nb_media> </td>
+   </tr>
+   <tr><td>Taille de la base :</td>      <td> <TMPL_VAR db_size> </td>
+       <td>Nombre de Pools :</td>         <td> <TMPL_VAR nb_pool> </td>
+       <td>Nombre de Jobs :</td>         <td> <TMPL_VAR nb_job> </td>
+   </tr>
+   <tr><td>Job en erreur (<TMPL_VAR label>):</td> 
+       
+<td <TMPL_IF nb_err> class='joberr' </TMPL_IF>>
+   <TMPL_VAR nb_err> 
+</td>
+       <td></td>         <td></td>
+       <td></td>         <td></td>
+   </tr>
+  
+  </table>
+</div>
diff --git a/gui/bweb/lang/fr/tpl/graph.tpl b/gui/bweb/lang/fr/tpl/graph.tpl
new file mode 100644 (file)
index 0000000..25e82aa
--- /dev/null
@@ -0,0 +1,172 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'>Statistiques</h1>
+ </div>
+ <div class='bodydiv'>
+<table border='0'>
+<td>
+<form name='form1' action='?' method='GET'>
+       <div class="otherboxtitle">
+          Options &nbsp;
+        </div>
+        <div class="otherbox">
+<table border='0'>
+<tr>
+  <td valign='top'>
+    <h2>Niveau</h2>
+    <select name='level' class='formulaire'>
+      <option id='level_Any' value='Any'>Tous</option>
+      <option id='level_F' value='F'>Full</option>
+      <option id='level_D' value='D'>Differentielle</option>
+      <option id='level_I' value='I'>Incrémentale</option>
+    </select>     
+  </td><td valign='top'>
+    <h2>Statut</h2>
+    <select name='status' class='formulaire'>
+      <option id='status_Any' value='Any'>Tous</option>
+      <option id='status_T'   value='T'>Ok</option>
+      <option id='status_f'   value='f'>Erreur</option>
+      <option id='status_A'   value='A'>Annulé</option>
+    </select>   
+  </td>
+</tr>
+<tr>
+  <td valign='top'>
+    <h2>Période</h2>
+    <select name='age' class='formulaire'>
+      <option id='age_604800'   value='604800'>Cette semaine</option>
+      <option id='age_2678400'  value='2678400'>30 derniers jours</option>
+      <option id='age_15552000' value='15552000'>6 derniers mois</option>
+    </select>     
+  </td>
+  <td  valign='top'>
+    <h2>Taille</h2>
+     Largeur : &nbsp;<input class='formulaire' type='text' 
+                        name='width' value='<TMPL_VAR width>' size='4'><br/>
+     Hauteur :  <input type='text' class='formulaire' 
+               name='height' value='<TMPL_VAR height>' size='4'><br/>
+  </td>
+</tr>
+<tr>
+  <td valign='top'> 
+    <h2>Clients</h2>
+    <select name='client' size='15' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_clients>
+      <option id='client_<TMPL_VAR clientname>'><TMPL_VAR clientname></option>
+</TMPL_LOOP>
+    </select>
+  </td>
+  <td valign='top'> 
+    <h2>Job</h2>
+    <select name='jobname' size='15' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_jobnames>
+      <option><TMPL_VAR NAME=jobname></option>
+</TMPL_LOOP>
+    </select>
+  </td>
+</tr>
+<tr>
+  <td> <h2> Type </h2> 
+ <select name='graph' class='formulaire'>
+   <option id='job_size'     value='job_size' title="Taille des jobs pour la période">Taille des Job </option>
+   <option id='job_duration' value='job_duration' title="Durée des jobs pour la période">Durée</option>
+   <option id='job_rate' value='job_rate' title="Débit des job pour la période">Débit</option>
+   <option id='job_file' value='job_file' title="Nombre de fichier sauvegardé par job pour la période">Nb fichiers</option>
+   <option id='job_count_phour' value='job_count_phour' title="Number of job per hour for the period">Job per hour</option>
+   <option id='job_count_pday' value='job_count_pday' title="Number of job per day for the period">Job per day</option>
+   <option id='job_avg_phour' value='job_avg_pday' title="Average backup size per day for the period">Job avg B/hour</option>
+   <option id='job_avg_pday' value='job_avg_pday' title="Average backup size per hour for the period">Job avg B/day</option>
+   <option id='job_sum_phour' value='job_sum_phour' title="Job size per hour">Job total B/hour</option>
+   <option id='job_sum_pday' value='job_sum_pday' title="Job size per day">Job total B/day</option>
+   <option id='job_count_hour' value='job_count_hour' title="Number of job per hour for the period">Jobs Count (h)</option>
+   <option id='job_count_day' value='job_count_day' title="Number of job per day for the period">Jobs Count (d)</option>
+   <option id='job_avg_hour' value='job_avg_hour' title="Average backup size per hour for the period">Job avg size (h)</option>
+   <option id='job_avg_day' value='job_avg_day' title="Average backup size per day for the period">Job avg size (d)</option>
+   <option id='job_sum_hour' value='job_sum_hour' title="Job size per hour for the period">Job Bytes (h)</option>
+   <option id='job_sum_day' value='job_sum_day' title="Job size per day for the period">Job Bytes (d)</option>
+ </select>
+  </td>
+  <td valign='bottom'> 
+    <h2>Nombre d'élément</h2>
+    <input type='text' name='limit' value='<TMPL_VAR NAME=limit>' 
+       class='formulaire' size='4'>
+  </td>
+</tr>
+<tr>
+<td><h2> Type de graphique </h2> 
+  <select name='gtype' class='formulaire'>
+    <option id='gtype_bars' value='bars'>Barres</option>
+<!--  <option id='gtype_bars3d' value='bars3d'>Bars3d</option> -->
+    <option id='gtype_lines' value='lines'>Lignes</option>
+    <option id='gtype_linespoints' value='linespoints'>Lignes avec points</option>
+</td>
+<td>
+  <input type='submit' name='action' value='graph' class='formulaire'> 
+</td>
+</tr>
+</table>
+        </div>
+
+</form>
+</td>
+<td>
+
+ <div class="otherboxtitle">
+ Graphique &nbsp;
+ </div>
+ <div class="otherbox">
+ <img src='bgraph.pl?<TMPL_VAR NAME=url>' alt="Rien n'a afficher, essayer avec une autre période">
+ </div>
+
+</td>
+</table>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+  <TMPL_LOOP qclients>
+     document.getElementById('client_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+  <TMPL_IF status>
+     document.getElementById('status_<TMPL_VAR status>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF level>
+     document.getElementById('level_<TMPL_VAR level>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF age>
+     document.getElementById('age_<TMPL_VAR age>').selected=true;
+  </TMPL_IF>
+
+<TMPL_IF qfilesets>
+  for (var i=0; i < document.form1.fileset.length; ++i) {
+  <TMPL_LOOP qfilesets>
+     if (document.form1.fileset[i].value == <TMPL_VAR name>) {
+        document.form1.fileset[i].selected = true;
+     }
+  </TMPL_LOOP>
+  }
+</TMPL_IF>
+
+<TMPL_IF qjobnames>
+  for (var i=0; i < document.form1.jobname.length; ++i) {
+  <TMPL_LOOP qjobnames>
+     if (document.form1.jobname[i].value == <TMPL_VAR name>) {
+        document.form1.jobname[i].selected = true;
+     }
+  </TMPL_LOOP>
+  }
+</TMPL_IF>
+
+  <TMPL_IF graph>
+     document.getElementById('<TMPL_VAR graph>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF gtype>
+     document.getElementById('gtype_<TMPL_VAR gtype>').selected=true;
+  </TMPL_IF>
+
+</script>
+
diff --git a/gui/bweb/lang/fr/tpl/help_extern.tpl b/gui/bweb/lang/fr/tpl/help_extern.tpl
new file mode 100644 (file)
index 0000000..f45f53e
--- /dev/null
@@ -0,0 +1,46 @@
+<br/>
+<div class='titlediv'>
+ <h1 class='newstitle'> Assistant d'externalisation de médias (partie 1/2)</h1>
+</div>
+<div class='bodydiv'>
+Cet outil va sélectionner pour vous les meilleurs cartouches Ã  externaliser.
+Vous devrez choisir parmi la sélection de l'écran suivant.
+
+  <form action="?" method='GET'>
+   <table>
+    <tr><td>Pool :</td>      
+        <td><select name='pool' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_pools>
+             <option><TMPL_VAR NAME=name></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td>Type de média:</td>      
+        <td><select name='mediatype' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_mediatypes>
+             <option><TMPL_VAR NAME=mediatype></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td> Localisation : </td>
+        <td><select name='location' class='formulaire'>
+  <TMPL_LOOP NAME=db_locations>
+      <option id='loc_<TMPL_VAR NAME=location>' value='<TMPL_VAR NAME=location>'><TMPL_VAR NAME=location></option>
+  </TMPL_LOOP>
+    </select>
+        </td>
+    </tr>
+    <tr>
+        <td>Nombre de médias <br/> Ã  externaliser :</td> 
+        <td> <input type='text' name='limit' size='3' class='formulaire' 
+              value='10'> </td>
+    </tr>
+    <tr>
+        <td><input type="image" name='action' value='compute_extern_media' title='Suivant' src='/bweb/next.png'>
+        </td><td/>
+    </tr>
+   </table>
+   </form>
+</div>
diff --git a/gui/bweb/lang/fr/tpl/help_extern_compute.tpl b/gui/bweb/lang/fr/tpl/help_extern_compute.tpl
new file mode 100644 (file)
index 0000000..3322739
--- /dev/null
@@ -0,0 +1,67 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Assistant d'externalisation de médias (partie 2/2)</h1>
+ </div>
+ <div class='bodydiv'>
+  Maintenant, vous devez vérifier la sélection et Ã©jecter les médias.
+   <form action='?' method='get'>
+    <table id='compute'></table>
+    <table><tr>
+    <td style='align: left;'>
+    <input type="image" onclick='javascript:window.history.go(-2);' title='Précédent' src='/bweb/prev.png'>
+    </td><td style='align: right;'>
+    <input type="image" name='action' value='extern' src='/bweb/extern.png' title='Externaliser la selection'>
+   </td></tr>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Nom de volume","Statut",
+                      "Type de média","Pool","Dernière Ã©criture", 
+                       "Expiration", "Sélection");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP NAME=Medias>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.value = '<TMPL_VAR NAME=volumename>';
+chkbox.name  = 'media';
+chkbox.checked = 'on';
+
+data.push( new Array(
+"<TMPL_VAR NAME=volumename>",
+"<TMPL_VAR NAME=volstatus>",
+"<TMPL_VAR NAME=mediatype>",
+"<TMPL_VAR NAME=name>",
+"<TMPL_VAR NAME=lastwritten>",
+"<TMPL_VAR NAME=expire>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "compute",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6)
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/lang/fr/tpl/help_intern.tpl b/gui/bweb/lang/fr/tpl/help_intern.tpl
new file mode 100644 (file)
index 0000000..82483b3
--- /dev/null
@@ -0,0 +1,53 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Assistant d'internalisation de médias (partie 1/2)</h1>
+</div>
+<div class="bodydiv">
+Cet outil va sélectionner pour vous les meilleurs cartouches Ã  internaliser.
+Vous devrez choisir parmi la sélection de l'écran suivant.
+
+  <form action="?" method='GET'>
+   <table>
+    <tr><td>Pool :</td>      
+        <td><select name='pool' class='formulaire' multiple>
+<TMPL_LOOP db_pools>
+             <option><TMPL_VAR name></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td>Type de média :</td>      
+        <td><select name='mediatype' class='formulaire' multiple>
+<TMPL_LOOP db_mediatypes>
+             <option><TMPL_VAR mediatype></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td>
+    Localisation : 
+    </td><td><select name='location' class='formulaire'>
+  <TMPL_LOOP db_locations>
+      <option value='<TMPL_VAR location>'><TMPL_VAR location></option>
+  </TMPL_LOOP>
+    </select>
+    </td>
+    </tr>
+    <tr>
+        <td>Choisir des médias <br/> expirés :</td> 
+        <td> <input type='checkbox' name='expired' class='formulaire' 
+               checked> </td>
+    </tr>
+    <tr>
+        <td>Nombre de médias <br/> Ã  internaliser :</td> 
+        <td> <input type='text' name='limit' class='formulaire' 
+               size='3' value='10'> </td>
+    </tr>
+    <tr>
+        <td><input type="image" name='action' value='compute_intern_media' 
+               title='Suivant' src='/bweb/next.png'>
+        </td><td/>
+    </tr>
+   </table>
+   </form>
+</div>
diff --git a/gui/bweb/lang/fr/tpl/help_intern_compute.tpl b/gui/bweb/lang/fr/tpl/help_intern_compute.tpl
new file mode 100644 (file)
index 0000000..b08a983
--- /dev/null
@@ -0,0 +1,69 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Assistant d'internalisation de médias (partie 2/2)</h1>
+ </div>
+ <div class='bodydiv'>
+  Maintenant vous devez vérifier la sélection et charger les médias.
+
+   <form action='?' method='get'>
+    <table id='compute'></table>
+    <table><tr>
+    <td style='align: left;'>
+    <input type="image" onclick='javascript:window.history.go(-2);' title='Précédent' src='/bweb/prev.png'>
+    </td><td style='align: right;'>
+    <input type="image" name='action' value='move_media'
+     src='/bweb/intern.png'>
+   </td></tr>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Nom de volume","Statut",
+                      "Type de media","Pool","Dernière Ã©criture", 
+                       "Expiration", "Sélection");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP NAME=Medias>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.name = 'media';
+chkbox.value= '<TMPL_VAR NAME=volumename>';
+chkbox.checked = 'on';
+
+data.push( new Array(
+"<TMPL_VAR NAME=volumename>",
+"<TMPL_VAR NAME=volstatus>",
+"<TMPL_VAR NAME=mediatype>",
+"<TMPL_VAR NAME=name>",
+"<TMPL_VAR NAME=lastwritten>",
+"<TMPL_VAR NAME=expire>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "compute",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6)
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/lang/fr/tpl/location_add.tpl b/gui/bweb/lang/fr/tpl/location_add.tpl
new file mode 100644 (file)
index 0000000..f85c009
--- /dev/null
@@ -0,0 +1,28 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Ajouter une localisation </h1>
+</div>
+<div class='bodydiv'>
+   <form action="?" method='get'>
+    <table>
+     <tr><td>Localisation :</td>     
+         <td> 
+          <input class="formulaire" type='text' value='' size='32' name='location'> 
+         </td>
+     </tr>
+     <tr><td>Coût :</td> 
+         <td> <input class="formulaire" type='text' value='10' name='cost' size='3'>
+         </td>
+     </tr>
+     <tr><td>Enabled :</td> 
+         <td> <input class="formulaire" type='checkbox' value='10' name='enabled'>
+         </td>
+     </tr>
+    </table>
+    <input type="image" name='action' value='location_add' title="Sauvegarder"
+      src='/bweb/save.png'>
+   </form>
+
+Tips: Vous devez avoir une localisation par robotique.
+
+</div>
diff --git a/gui/bweb/lang/fr/tpl/location_edit.tpl b/gui/bweb/lang/fr/tpl/location_edit.tpl
new file mode 100644 (file)
index 0000000..ef19686
--- /dev/null
@@ -0,0 +1,26 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Localisation : <TMPL_VAR Location></h1>
+</div>
+<div class='bodydiv'>
+   <form action="?" method='get'>
+    <input type='hidden' name='location' value='<TMPL_VAR location>'>
+    <table>
+     <tr><td>Localisation :</td>     
+         <td> 
+          <input class="formulaire" type='text' value='<TMPL_VAR location>' size='32' name='newlocation'> 
+         </td>
+     </tr>
+     <tr><td>Coût :</td> 
+         <td> <input class="formulaire" type='text' value='<TMPL_VAR cost>' name='cost' size='3'>
+         </td>
+     </tr>
+     <tr><td>Enabled :</td> 
+         <td> <input class="formulaire" type='checkbox' name='enabled' <TMPL_IF enabled> checked </TMPL_IF> >
+         </td>
+     </tr>
+    </table>
+    <input type="image" name='action' value='location_save'
+     src='/bweb/save.png'>
+   </form>
+</div>
diff --git a/gui/bweb/lang/fr/tpl/move_media.tpl b/gui/bweb/lang/fr/tpl/move_media.tpl
new file mode 100644 (file)
index 0000000..baca0f4
--- /dev/null
@@ -0,0 +1,85 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'>Déplacer un média</h1>
+ </div>
+ <div class="bodydiv">
+   <form action='?' method='get'>
+    <table id='id<TMPL_VAR NAME=ID>'></table>
+    <table border='0'>
+    <tr><td> Nouvelle localisation : </td><td>
+<select name='newlocation' class='formulaire'>
+    <TMPL_LOOP NAME=db_locations>
+    <option value='<TMPL_VAR NAME=location>'><TMPL_VAR NAME=location></option>
+    </TMPL_LOOP>
+</select>
+    </td></tr><tr><td> Statut : </td><td>
+<select name='volstatus' class='formulaire'>
+    <option value=''>Ne pas modifier</option>
+    <option value='Append'>Append</option>
+    <option value='Archive'>Archive</option>
+    <option value='Disabled'>Disabled</option>
+    <option value='Cleaning'>Cleaning</option>
+    <option value='Error'>Error</option>
+    <option value='Full'>Full</option>
+    <option value='Purged'>Purged</option>
+    <option value='Read-Only'>Read-Only</option>
+    <option value='Recycle'>Recycle</option>
+    <option value='Used'>Used</option>
+</select>
+    </td><tr><td> Utilisateur : </td><td>
+<input type='text' name='user' value='<TMPL_VAR loginname>' class='formulaire'>
+    </td></tr>
+    </td></tr><tr><td> Commentaire : </td><td>
+<textarea name="comment" class='formulaire'></textarea>
+    </td></tr>
+    </table>
+    <label>
+    <input type="image" type='submit' name='action' value='change_location' src='/bweb/apply.png'> Déplacer
+    </label>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Nom de volume", "Localisation", "Sélection");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP NAME=medias>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.value = '<TMPL_VAR name=volumename>';
+chkbox.name  = 'media';
+chkbox.checked = 1;
+
+data.push( new Array(
+"<TMPL_VAR NAME=volumename>",
+"<TMPL_VAR NAME=location>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR NAME=ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6),
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/lang/fr/tpl/run_job.tpl b/gui/bweb/lang/fr/tpl/run_job.tpl
new file mode 100644 (file)
index 0000000..bda7494
--- /dev/null
@@ -0,0 +1,33 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Jobs définis : </h1>
+ </div>
+ <div class='bodydiv'>
+  <form name='form1' action='?' method='GET'>  
+  <table border='0'>
+
+   <tr><td>Nom du job : </td><td>
+   <select name='job'>
+    <TMPL_LOOP jobs>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+   </td></tr>
+   </table>
+   <br/>
+   <label>
+   <input type="image" name='action' value='enable_job' title='Activer'
+    src='/bweb/inflag1.png'> Activer
+   </label>
+   <label>
+   <input type="image" name='action' value='disable_job' title='Désactiver'
+    src='/bweb/inflag0.png'> Désactiver
+   </label>
+   <label>
+   <input type="image" name='action' value='run_job_mod' title='Lancer maintenant'
+    src='/bweb/R.png'> Lancer maintenant
+   </label>
+  </form>
+ </div>
diff --git a/gui/bweb/lang/fr/tpl/run_job_mod.tpl b/gui/bweb/lang/fr/tpl/run_job_mod.tpl
new file mode 100644 (file)
index 0000000..4bf8ea2
--- /dev/null
@@ -0,0 +1,138 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Lancer le job : <TMPL_VAR job> sur <TMPL_VAR client></h1>
+ </div>
+ <div class='bodydiv'>
+  <form name='form1' action='?' method='GET'>  
+  <table border='0'>
+
+   <tr><td>Nom du job : </td><td>
+   <select name='job'>
+    <TMPL_LOOP jobs>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+   </td></tr><tr><td>Pool : </td><td>
+
+   <select name='pool'>        
+     <option value=''></option>
+    <TMPL_LOOP pools>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+   </td></tr><tr><td>Client : </td><td>
+
+   <select name='client'>
+    <TMPL_LOOP clients>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+
+   </td></tr><tr><td>FileSet : </td><td>
+   <select name='fileset'>
+    <TMPL_LOOP filesets>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+
+   </td></tr><tr><td>Storage : </td><td>
+   <select name='storage'>
+    <TMPL_LOOP storages>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+
+   </td></tr><tr><td>Niveau : </td><td>
+   <select name='level'>
+     <option id='level_Incremental' value='Incremental'>Incrémentale</option>
+     <option id='level_Full' value='Full'>Full</option>
+     <option id='level_Differential' value='Differential'>Différentielle</option>
+   </select>
+   </td></tr><tr id='more1' style="visibility:hidden"><td>Start Time: </td><td>
+   <input class='formulaire' 
+         type='text' title='YYYY-MM-DD HH:MM:SS'
+          size='17' name='when' value='<TMPL_VAR when>'>
+
+   </td></tr><tr id='more2' style="visibility:hidden"><td>Priorité : </td><td>
+   <input class='formulaire' type='text' 
+          size='3' name='priority' value='<TMPL_VAR priority>'>
+
+   </td></tr>
+   </table>
+   <br/>
+  <label onclick='
+           document.getElementById("more1").style.visibility="visible";
+           document.getElementById("more2").style.visibility="visible";'>
+  <img title="Affiche plus d'options" src='/bweb/add.png'>Options</label>
+  <label>
+  <label>
+  <input type="image" name='action' value='run_job_now' title='Lancer maintenant'
+   src='/bweb/R.png'>Lancer maintenant
+  </label>
+  <label>
+  <input type="image" name='action' value='fileset_view' title='Voir le FileSet'
+   src='/bweb/zoom.png'>Voir le FileSet
+  </label>
+  </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+  <TMPL_IF job>
+     ok=1;
+     for(var i=0; ok && i < document.form1.job.length; i++) {
+       if (document.form1.job[i].value == '<TMPL_VAR job>') {
+           document.form1.job[i].selected=true;
+           ok=0;
+       }
+     }
+  </TMPL_IF>
+  <TMPL_IF client>
+     ok=1;
+     for(var i=0; ok && i < document.form1.client.length; i++) {
+       if (document.form1.client[i].value == '<TMPL_VAR client>') {
+           document.form1.client[i].selected=true;
+           ok=0;
+       }
+     }
+  </TMPL_IF>
+  <TMPL_IF pool>
+     ok=1;
+     for(var i=0; ok && i < document.form1.pool.length; i++) {
+       if (document.form1.pool[i].value == '<TMPL_VAR pool>') {
+           document.form1.pool[i].selected=true;
+           ok=0;
+       }
+     }
+  </TMPL_IF>
+  <TMPL_IF storage>
+     ok=1;
+     for(var i=0; ok && i < document.form1.storage.length; i++) {
+       if (document.form1.storage[i].value == '<TMPL_VAR storage>') {
+           document.form1.storage[i].selected=true;
+           ok=0;
+       }
+     }
+  </TMPL_IF>
+  <TMPL_IF level>
+<!--     document.getElementById('level_<TMPL_VAR level>').selected=true; -->
+  </TMPL_IF>
+  <TMPL_IF fileset>
+     ok=1;
+     for(var i=0; ok && i < document.form1.fileset.length; i++) {
+       if (document.form1.fileset[i].value == '<TMPL_VAR fileset>') {
+           document.form1.fileset[i].selected=true;
+           ok=0;
+       }
+     }
+  </TMPL_IF>
+</script>
diff --git a/gui/bweb/lang/fr/tpl/running_job.tpl b/gui/bweb/lang/fr/tpl/running_job.tpl
new file mode 100644 (file)
index 0000000..9d9ffac
--- /dev/null
@@ -0,0 +1,96 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Jobs en cours </h1>
+ </div>
+ <div class='bodydiv'>
+   <form action='?' method='GET'>
+   <table id='id<TMPL_VAR NAME=ID>'></table>
+   <br/>
+<label>
+<input type='image' name='action' value='dsp_cur_job' 
+ title='Voir le job' src='/bweb/zoom.png'>
+</label>
+<label>
+<input type="image" type='submit' name='action' value='cancel_job'
+ onclick="return confirm('Vous voulez vraiment annuler ce job ?')"
+ title='Annuler le job' src='/bweb/cancel.png'>
+</label>
+   </form>
+
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+var header = new Array("JobId",
+                      "Client",
+                      "Nom du Job", 
+                       "Niveau",
+                       "Début", 
+                       "Durée", 
+//                       "Job Files",
+//                       "Job Bytes", 
+                      "Statut",
+                      "Sélection"
+       );
+
+var data = new Array();
+var chkbox;
+var img;
+
+<TMPL_LOOP NAME=Jobs>
+a = document.createElement('A');
+a.href='?action=dsp_cur_job;jobid=<TMPL_VAR JobId>';
+
+img = document.createElement("IMG");
+img.src = '/bweb/<TMPL_VAR NAME=JobStatus>.png';
+img.title = jobstatus['<TMPL_VAR NAME=JobStatus>'];
+
+a.appendChild(img);
+
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'radio';
+chkbox.name = 'jobid';
+chkbox.value = '<TMPL_VAR NAME=jobid>';
+
+data.push( new Array(
+"<TMPL_VAR NAME=JobId>",
+"<TMPL_VAR NAME=ClientName>",     
+"<TMPL_VAR NAME=JobName>",    
+joblevel['<TMPL_VAR NAME=Level>'],      
+"<TMPL_VAR NAME=StartTime>",
+"<TMPL_VAR NAME=duration>",
+//"<TMPL_VAR NAME=JobFiles>",   
+//"<TMPL_VAR NAME=JobBytes>",
+a,
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR NAME=ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: true,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+// disable_sorting: new Array(6)
+ padding: 3
+}
+);
+
+// get newest backup first
+nrsTables['id<TMPL_VAR NAME=ID>'].fieldSort(0);
+
+bweb_add_refresh();
+
+</script>
diff --git a/gui/bweb/lang/fr/tpl/scheduled_job.tpl b/gui/bweb/lang/fr/tpl/scheduled_job.tpl
new file mode 100644 (file)
index 0000000..0aa3e58
--- /dev/null
@@ -0,0 +1,71 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Prochains jobs </h1>
+ </div>
+ <div class='bodydiv'>
+    <form action='?' method='GET'>
+     <table id='id<TMPL_VAR ID>'></table>
+     <label>
+     <input type="image" name='action' value='run_job_mod'
+      src='/bweb/R.png' title='Lancer maintenant'> Lancer maintenant
+     </label>
+     <label>
+      <input type="image" name='action' value='disable_job'
+       src='/bweb/inflag0.png' title='Désactiver'> Désactiver
+      </label>
+    </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Quand",
+                       "Niveau",
+                      "Type",
+                      "Priorité", 
+                       "Nom",
+                       "Volume",
+                      "Sélection");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP list>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'radio';
+chkbox.name = 'job';
+chkbox.value = '<TMPL_VAR name>';
+
+data.push( new Array(
+"<TMPL_VAR date>",    
+"<TMPL_VAR level>",
+"<TMPL_VAR type>",     
+"<TMPL_VAR priority>",    
+"<TMPL_VAR name>",      
+"<TMPL_VAR volume>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: true,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+// disable_sorting: new Array(6),
+ padding: 3
+}
+);
+</script>
diff --git a/gui/bweb/lang/fr/tpl/stats.tpl b/gui/bweb/lang/fr/tpl/stats.tpl
new file mode 100644 (file)
index 0000000..de1d036
--- /dev/null
@@ -0,0 +1,9 @@
+<div class='titlediv'>
+  <h1 class='newstitle'> Statistiques </h1>
+</div>
+<div class='bodydiv'>
+<a href='?action=job;age=172800;jobtype=B'>
+<img width='450' height='200' src='bgraph.pl?age=2678400;width=450;height=200;graph=job_sum_day;limit=500;action=graph;legend=off' alt='Rien a afficher'>
+</a>
+</div>
+
diff --git a/gui/bweb/lang/fr/tpl/update_location.tpl b/gui/bweb/lang/fr/tpl/update_location.tpl
new file mode 100644 (file)
index 0000000..acc484c
--- /dev/null
@@ -0,0 +1,65 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'>Mise Ã  jour de la localisation d'un média</h1>
+ </div> 
+ <div class="bodydiv">
+   <form action='?' method='get'>
+    <table id='id<TMPL_VAR NAME=ID>'></table>
+    Nouvelle localisation : <select class='formulaire' name='newlocation'>
+   <TMPL_LOOP NAME=db_locations>
+      <option id='loc_<TMPL_VAR NAME=location>' value='<TMPL_VAR NAME=location>'><TMPL_VAR NAME=location></option>
+   </TMPL_LOOP>
+  </select>
+  <input type="image" name='action' value='save_location' src='/bweb/apply.png'>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Nom de volume", "Localisation", "Sélection");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP NAME=medias>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.value = '<TMPL_VAR name=volumename>';
+chkbox.name  = 'media';
+chkbox.checked = 1;
+
+data.push( new Array(
+"<TMPL_VAR NAME=volumename>",
+"<TMPL_VAR NAME=location>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR NAME=ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6)
+ rows_per_page: rows_per_page
+}
+);
+
+<TMPL_IF qnewlocation>
+ document.getElementById('loc_' + <TMPL_VAR qnewlocation>).selected=true;
+</TMPL_IF>
+
+</script>
diff --git a/gui/bweb/lang/fr/tpl/update_media.tpl b/gui/bweb/lang/fr/tpl/update_media.tpl
new file mode 100644 (file)
index 0000000..d43eebf
--- /dev/null
@@ -0,0 +1,156 @@
+<br/>
+<div class='titlediv'>
+ <h1 class='newstitle'> Modifier le media <TMPL_VAR volumename></h1>
+</div>
+<div class='bodydiv'>
+  <form name='form1' action="?" method='GET'>
+   <table>
+    <tr><td>Nom du volume :</td>
+        <td><input type='text' name='media' class='formulaire' value='<TMPL_VAR volumename>' title='Modifiez ce champs pour mettre Ã  jour un autre média'>
+        </td>
+    </tr>
+    <tr><td>Pool :</td>
+        <td><select name='pool' class='formulaire'>
+<TMPL_LOOP db_pools>
+             <option value='<TMPL_VAR name>'><TMPL_VAR name></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td>Statut :</td>
+        <td><select name='volstatus' class='formulaire'>
+           <option value='Append'>Append</option>
+           <option value='Archive'>Archive</option>
+           <option value='Disabled'>Disabled</option>
+           <option value='Cleaning'>Cleaning</option>
+           <option value='Error'>Error</option>
+          <option value='Full'>Full</option>
+           <option value='Read-Only'>Read-Only</option>
+           <option value='Used'>Used</option>
+           </select>
+        </td>
+    </tr>
+
+    <tr><td>Slot :</td>
+        <td> 
+          <input class='formulaire' type='text' 
+                 name='slot' value='<TMPL_VAR slot>'>
+        </td>
+    </tr>
+
+    <tr><td>En ligne :</td>
+        <td> 
+          <input class='formulaire' type='checkbox' 
+               name='inchanger' <TMPL_IF inchanger>checked</TMPL_IF>>
+        </td>
+    </tr>
+
+    <tr><td> Localisation : </td>
+        <td><select name='location' class='formulaire'>
+      <option value=''></option>
+  <TMPL_LOOP db_locations>
+      <option value='<TMPL_VAR location>'><TMPL_VAR location></option>
+  </TMPL_LOOP>
+    </select>
+        </td>
+    </tr>
+    <tr><td> Période de rétention : </td>
+        <td>
+          <input class='formulaire' type='text' title='ex: 3 days, 1 month'
+               name='volretention' value='<TMPL_VAR volretention>'>
+        </td>
+    </tr>
+    <tr><td> Durée d'utilisation : </td>
+        <td>
+          <input class='formulaire' type='text' title='ex: 3 days, 1 month'
+               name='voluseduration' value='<TMPL_VAR voluseduration>'>
+        </td>
+    </tr>
+    <tr><td> Nombre de jobs maxi : </td>
+        <td>
+          <input class='formulaire' type='text' title='ex: 10'
+               name='maxvoljobs' value='<TMPL_VAR maxvoljobs>'>
+        </td>
+    </tr>
+    <tr><td> Nombre de fichiers maxi : </td>
+        <td>
+          <input class='formulaire' type='text' title='ex: 10000'
+               name='maxvolfiles' value='<TMPL_VAR maxvolfiles>'>
+        </td>
+    </tr>
+    <tr><td> Taille maxi : </td>
+        <td>
+          <input class='formulaire' type='text' title='ex: 10M, 11G'
+               name='maxvolbytes' value='<TMPL_VAR maxvolbytes>'>
+        </td>
+    </tr>
+    <tr><td>Pool de recyclage :</td>
+        <td><select name='poolrecycle' class='formulaire'>
+<TMPL_LOOP db_pools>
+             <option value='<TMPL_VAR name>'><TMPL_VAR name></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td> Commentaire : </td>
+        <td>
+          <input class='formulaire' type='text' title='un commentaire'
+               name='comment' value='<TMPL_VAR comment>'>
+        </td>
+    </tr>
+    </table>
+<table>
+ <td>
+ <label>
+  <input type="image" name='action' value='do_update_media' src='/bweb/apply.png'> Appliquer
+  </label>
+  <label>
+  <input type="image" name='action' title='Mettre Ã  jour Ã  partir du pool'
+    value='update_from_pool' src='/bweb/update.png'> Reinitialiser
+  </label>
+ </form>
+ </td>
+ <td>
+  <form action='?' method='GET'>
+   <input type='hidden' name='pool' value='<TMPL_VAR poolname>'>
+   <label>
+    <input type="image" name='action' value='media'
+     src='/bweb/zoom.png'>Voir le pool
+   </label>
+  </form>
+ </td>
+</table>
+</div>
+
+<script type="text/javascript" language='JavaScript'>
+var ok=1;
+for (var i=0; ok && i < document.form1.pool.length; ++i) {
+   if (document.form1.pool[i].value == '<TMPL_VAR poolname>') {
+      document.form1.pool[i].selected = true;
+      ok=0;
+   }
+}
+ok=1;
+for (var i=0; ok && i < document.form1.poolrecycle.length; ++i) {
+   if (document.form1.poolrecycle[i].value == '<TMPL_VAR poolrecycle>') {
+      document.form1.poolrecycle[i].selected = true;
+      ok=0;
+   }
+}
+ok=1;
+for (var i=0; ok && i < document.form1.location.length; ++i) {
+   if (document.form1.location[i].value == '<TMPL_VAR location>') {
+      document.form1.location[i].selected = true;
+      ok=0;
+   }
+}
+
+ok=1;
+for (var i=0; ok && i < document.form1.volstatus.length; ++i) {
+   if (document.form1.volstatus[i].value == '<TMPL_VAR volstatus>') {
+      document.form1.volstatus[i].selected = true;
+      ok=0;
+   }
+}
+
+</script>
diff --git a/gui/bweb/lib/Bconsole.pm b/gui/bweb/lib/Bconsole.pm
new file mode 100644 (file)
index 0000000..f612d6e
--- /dev/null
@@ -0,0 +1,444 @@
+use strict;
+
+=head1 LICENSE
+
+   Bweb - A Bacula web interface
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+
+   The main author of Bweb is Eric Bollengier.
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation plus additions
+   that are listed in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
+   Switzerland, email:ftf@fsfeurope.org.
+
+=head1 VERSION
+
+    $Id$
+
+=cut
+
+
+################################################################
+# Manage with Expect the bconsole tool
+package Bconsole;
+use Expect;
+use POSIX qw/_exit/;
+
+# my $pref = new Pref(config_file => 'brestore.conf');
+# my $bconsole = new Bconsole(pref => $pref);
+sub new
+{
+    my ($class, %arg) = @_;
+
+    my $self = bless {
+       pref => $arg{pref},     # Pref object
+       bconsole => undef,      # Expect object
+       log_stdout => $arg{log_stdout} || 0,
+       timeout => $arg{timeout} || 20,
+       debug   => $arg{debug} || 0,
+    };
+
+    return $self;
+}
+
+sub run
+{
+    my ($self, %arg) = @_;
+
+    my $cmd = 'run ';
+    for my $key (keys %arg) {
+       if ($arg{$key}) {
+           $arg{$key} =~ tr/""/  /;
+           $cmd .= "$key=\"$arg{$key}\" ";
+       }
+    }
+
+    unless ($self->connect()) {
+       return 0;
+    }
+
+    print STDERR "===> $cmd yes\n";
+    $self->{bconsole}->clear_accum();
+    $self->send("$cmd yes\n");
+    $self->expect_it('-re',qr/^[*]/);
+    my $ret = $self->before();
+    if ($ret =~ /jobid=(\d+)/is) {
+       return $1;
+    } else {
+       return 0;
+    }
+}
+
+# for brestore.pl::BwebConsole
+sub prepare
+{
+    # do nothing
+}
+
+sub send
+{
+    my ($self, $what) = @_;
+    $self->{bconsole}->send($what);
+}
+
+sub expect_it
+{
+    my ($self, @what) = @_;
+    unless ($self->{bconsole}->expect($self->{timeout}, @what)) {
+       $self->{error} = $!;
+       return 0;
+    }
+    return 1;
+}
+
+sub log_stdout
+{
+    my ($self, $how) = @_;
+
+    if ($self->{bconsole}) {
+       $self->{bconsole}->log_stdout($how);
+    }
+
+    $self->{log_stdout} = $how;
+}
+
+sub connect
+{
+    my ($self) = @_;
+
+    if ($self->{error}) {
+       return 0 ;
+    }
+
+    unless ($self->{bconsole}) {
+       my @cmd = split(/\s+/, $self->{pref}->{bconsole}) ;
+       unless (@cmd) {
+           $self->{error} = "bconsole string not found";
+           return 0;
+       }
+       $self->{bconsole} = new Expect;
+       $self->{bconsole}->raw_pty(0);
+       $self->{bconsole}->debug($self->{debug});
+       $self->{bconsole}->log_stdout($self->{debug} || $self->{log_stdout});
+
+       # WARNING : die is trapped by gtk_main_loop()
+       # and exit() closes DBI connection 
+       my $ret;
+       { 
+           my $sav = $SIG{__DIE__};
+           $SIG{__DIE__} = sub {  _exit 1 ;};
+            my $old = $ENV{COLUMNS};
+            $ENV{COLUMNS} = 300;
+           $ret = $self->{bconsole}->spawn(@cmd) ;
+            $ENV{COLUMNS} = $old;
+           $SIG{__DIE__} = $sav;
+       }
+
+       unless ($ret) {
+           $self->{error} = $!;
+           return 0;
+       }
+       
+       # TODO : we must verify that expect return the good value
+
+       $self->expect_it('*');
+       $self->send_cmd('gui on');
+    }
+    return 1 ;
+}
+
+sub cancel
+{
+    my ($self, $jobid) = @_;
+    return $self->send_cmd("cancel jobid=$jobid");
+}
+
+# get text between to expect
+sub before
+{
+    my ($self) = @_;
+    return $self->{bconsole}->before();
+}
+
+sub send_cmd
+{
+    my ($self, $cmd) = @_;
+    unless ($self->connect()) {
+       return '';
+    }
+    $self->send("$cmd\n");
+    $self->expect_it($cmd);
+    $self->{bconsole}->clear_accum();
+    $self->expect_it('-re',qr/^[*]/);
+    return $self->before();
+}
+
+sub send_cmd_yes
+{
+    my ($self, $cmd) = @_;
+    unless ($self->connect()) {
+       return '';
+    }
+    $self->send("$cmd\n");
+    $self->expect_it('-re', '[?].+:');
+
+    $self->send("yes\n");
+    $self->expect_it("yes");
+    $self->{bconsole}->clear_accum();
+    $self->expect_it('-re',qr/^[*]/);
+    return $self->before();
+}
+
+sub label_barcodes
+{
+    my ($self, %arg) = @_;
+
+    unless ($arg{storage}) {
+       return '';
+    }
+
+    unless ($self->connect()) {
+       return '';
+    }
+
+    $arg{drive} = $arg{drive} || '0' ;
+    $arg{pool} = $arg{pool} || 'Scratch';
+
+    my $cmd = "label barcodes drive=$arg{drive} pool=\"$arg{pool}\" storage=\"$arg{storage}\"";
+
+    if ($arg{slots}) {
+       $cmd .= " slots=$arg{slots}";
+    }
+
+    $self->send("$cmd\n");
+    $self->expect_it('-re', '[?].+\).*:');
+    my $res = $self->before();
+    $self->send("yes\n");
+    $self->expect_it("yes");
+    $res .= $self->before();
+    $self->expect_it('-re',qr/^[*]/);
+    $res .= $self->before();
+    return $res;
+}
+
+#
+# return [ { name => 'test1', vol => '00001', ... },
+#          { name => 'test2', vol => '00002', ... }... ] 
+#
+sub director_get_sched
+{
+    my ($self, $days) = @_ ;
+
+    $days = $days || 1;
+
+    unless ($self->connect()) {
+       return '';
+    }
+   
+    my $status = $self->send_cmd("st director days=$days") ;
+
+    my @ret;
+    foreach my $l (split(/\r?\n/, $status)) {
+       #Level          Type     Pri  Scheduled        Name       Volume
+       #Incremental    Backup    11  03-ao-06 23:05  TEST_DATA  000001
+       if ($l =~ /^(I|F|Di)\w+\s+\w+\s+\d+/i) {
+           my ($level, $type, $pri, $d, $h, @name_vol) = split(/\s+/, $l);
+
+           my $vol = pop @name_vol; # last element
+           my $name = join(" ", @name_vol); # can contains space
+
+           push @ret, {
+               level => $level,
+               type  => $type,
+               priority => $pri,
+               date  => "$d $h",
+               name  => $name,
+               volume => $vol,
+           };
+       }
+
+    }
+    return \@ret;
+}
+
+sub update_slots
+{
+    my ($self, $storage, $drive) = @_;
+    $drive = $drive || 0;
+
+    return $self->send_cmd("update slots storage=$storage drive=$drive");
+}
+
+sub get_fileset
+{
+    my ($self, $fs) = @_;
+
+    my $out = $self->send_cmd("show fileset=\"$fs\"");
+    
+    my $ret = {};
+
+    foreach my $l (split(/\r\n/, $out)) { 
+        #              I /usr/local
+       if ($l =~ /^\s+([I|E])\s+(.+)$/) { # include
+           push @{$ret->{$1}}, { file => $2 };
+       }
+    }
+
+    return $ret;
+}
+
+sub list_job
+{
+    my ($self) = @_;
+    return split(/\r\n/, $self->send_cmd(".jobs"));
+}
+
+sub list_fileset
+{
+    my ($self) = @_;
+    return split(/\r\n/, $self->send_cmd(".filesets"));
+}
+
+sub list_storage
+{
+    my ($self) = @_;
+    return split(/\r\n/, $self->send_cmd(".storage"));
+}
+
+sub list_client
+{
+    my ($self) = @_;
+    return split(/\r\n/, $self->send_cmd(".clients"));
+}
+
+sub list_pool
+{
+    my ($self) = @_;
+    return split(/\r\n/, $self->send_cmd(".pools"));
+}
+
+use Time::ParseDate qw/parsedate/;
+use POSIX qw/strftime/;
+use Data::Dumper;
+
+sub _get_volume
+{
+    my ($self, @volume) = @_;
+    return '' unless (@volume);
+
+    my $sel='';
+    foreach my $vol (@volume) {
+       if ($vol =~ /^([\w\d\.-]+)$/) {
+           $sel .= " volume=$1";
+
+       } else {
+           $self->{error} = "Sorry media is bad";
+           return '';
+       }
+    }
+
+    return $sel;
+}
+
+sub purge_volume
+{
+    my ($self, @volume) = @_;
+
+    my $sel = $self->_get_volume(@volume);
+    my $ret;
+    if ($sel) {
+       $ret = $self->send_cmd("purge $sel");
+    } else {
+       $ret = $self->{error};
+    }
+    return $ret;
+}
+
+sub prune_volume
+{
+    my ($self, @volume) = @_;
+
+    my $sel = $self->_get_volume(@volume);
+    my $ret;
+    if ($sel) {
+       $ret = $self->send_cmd("prune $sel yes");
+    } else {
+       $ret = $self->{error};
+    }
+    return $ret;
+}
+
+sub purge_job
+{
+    my ($self, @jobid) = @_;
+
+    return 0 unless (@jobid);
+
+    my $sel='';
+    foreach my $job (@jobid) {
+       if ($job =~ /^(\d+)$/) {
+           $sel .= " jobid=$1";
+
+       } else {
+           $self->{error} = "Sorry jobid is bad";
+           return 0;
+       }
+    }
+
+    $self->send_cmd("purge $sel");
+}
+
+sub close
+{
+    my ($self) = @_;
+    $self->send("quit\n");
+    $self->{bconsole}->soft_close();
+    $self->{bconsole} = undef;
+}
+
+1;
+
+__END__
+
+# to use this
+# grep -v __END__ Bconsole.pm | perl
+
+package main;
+
+print "test sans conio\n";
+
+my $c = new Bconsole(pref => {
+    bconsole => '/tmp/bacula/sbin/bconsole -n -c /tmp/bacula/etc/bconsole.conf',
+},
+                    debug => 0);
+
+print "fileset : ", join(',', $c->list_fileset()), "\n";
+print "job : ",     join(',', $c->list_job()), "\n";
+print "storage : ", join(',', $c->list_storage()), "\n";
+#print "prune : " . $c->prune_volume('000001'), "\n";
+#print "update : " . $c->send_cmd('update slots storage=SDLT-1-2, drive=0'), "\n";
+#print "label : ", join(',', $c->label_barcodes(storage => 'SDLT-1-2',
+#                                             slots => 6,
+#                                             drive => 0)), "\n";
+
+
diff --git a/gui/bweb/lib/Bweb.pm b/gui/bweb/lib/Bweb.pm
new file mode 100644 (file)
index 0000000..cd264ee
--- /dev/null
@@ -0,0 +1,3280 @@
+################################################################
+use strict;
+
+=head1 LICENSE
+
+   Bweb - A Bacula web interface
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+
+   The main author of Bweb is Eric Bollengier.
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation plus additions
+   that are listed in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
+   Switzerland, email:ftf@fsfeurope.org.
+
+=head1 VERSION
+
+    $Id$
+
+=cut
+
+package Bweb::Gui;
+
+=head1 PACKAGE
+
+    Bweb::Gui - Base package for all Bweb object
+
+=head2 DESCRIPTION
+
+    This package define base fonction like new, display, etc..
+
+=cut
+
+use HTML::Template;
+our $template_dir='/usr/share/bweb/tpl';
+
+=head1 FUNCTION
+
+    new - creation a of new Bweb object
+
+=head2 DESCRIPTION
+
+    This function take an hash of argument and place them
+    on bless ref
+
+    IE : $obj = new Obj(name => 'test', age => '10');
+
+         $obj->{name} eq 'test' and $obj->{age} eq 10
+
+=cut
+
+sub new
+{
+    my ($class, %arg) = @_;
+    my $self = bless {
+       name => undef,
+    }, $class;
+
+    map { $self->{lc($_)} = $arg{$_} } keys %arg ;
+
+    return $self;
+}
+
+sub debug
+{
+    my ($self, $what) = @_;
+
+    if ($self->{debug}) {
+       if (ref $what) {
+           print "<pre>" . Data::Dumper::Dumper($what) . "</pre>";
+       } else {
+           print "<pre>$what</pre>";
+       }
+    }
+}
+
+=head1 FUNCTION
+
+    error - display an error to the user
+
+=head2 DESCRIPTION
+
+    this function set $self->{error} with arg, display a message with
+    error.tpl and return 0
+
+=head2 EXAMPLE
+
+    unless (...) {
+        return $self->error("Can't use this file");
+    }
+
+=cut
+
+sub error
+{
+    my ($self, $what) = @_;
+    $self->{error} = $what;
+    $self->display($self, 'error.tpl');
+    return 0;
+}
+
+=head1 FUNCTION
+
+    display - display an html page with HTML::Template
+
+=head2 DESCRIPTION
+
+    this function is use to render all html codes. it takes an
+    ref hash as arg in which all param are usable in template.
+
+    it will use global template_dir to search the template file.
+
+    hash keys are not sensitive. See HTML::Template for more
+    explanations about the hash ref. (it's can be quiet hard to understand) 
+
+=head2 EXAMPLE
+
+    $ref = { name => 'me', age => 26 };
+    $self->display($ref, "people.tpl");
+
+=cut
+
+sub display
+{
+    my ($self, $hash, $tpl) = @_ ;
+    
+    my $template = HTML::Template->new(filename => $tpl,
+                                      path =>[$template_dir],
+                                      die_on_bad_params => 0,
+                                      case_sensitive => 0);
+
+    foreach my $var (qw/limit offset/) {
+
+       unless ($hash->{$var}) {
+           my $value = CGI::param($var) || '';
+
+           if ($value =~ /^(\d+)$/) {
+               $template->param($var, $1) ;
+           }
+       }
+    }
+
+    $template->param('thisurl', CGI::url(-relative => 1, -query=>1));
+    $template->param('loginname', CGI::remote_user());
+
+    $template->param($hash);
+    print $template->output();
+}
+1;
+
+################################################################
+
+package Bweb::Config;
+
+use base q/Bweb::Gui/;
+
+=head1 PACKAGE
+    
+    Bweb::Config - read, write, display, modify configuration
+
+=head2 DESCRIPTION
+
+    this package is used for manage configuration
+
+=head2 USAGE
+
+    $conf = new Bweb::Config(config_file => '/path/to/conf');
+    $conf->load();
+
+    $conf->edit();
+
+    $conf->save();
+
+=cut
+
+use CGI;
+
+=head1 PACKAGE VARIABLE
+
+    %k_re - hash of all acceptable option.
+
+=head2 DESCRIPTION
+
+    this variable permit to check all option with a regexp.
+
+=cut
+
+our %k_re = ( dbi      => qr/^(dbi:(Pg|mysql):(?:\w+=[\w\d\.-]+;?)+)$/i,
+             user     => qr/^([\w\d\.-]+)$/i,
+             password => qr/^(.*)$/i,
+             fv_write_path => qr!^([/\w\d\.-]*)$!,
+             template_dir => qr!^([/\w\d\.-]+)$!,
+             debug    => qr/^(on)?$/,
+             email_media => qr/^([\w\d\.-]+@[\d\w\.-]+)$/,
+             graph_font  => qr!^([/\w\d\.-]+.ttf)$!,
+             bconsole    => qr!^(.+)?$!,
+             syslog_file => qr!^(.+)?$!,
+             log_dir     => qr!^(.+)?$!,
+             );
+
+=head1 FUNCTION
+
+    load - load config_file
+
+=head2 DESCRIPTION
+
+    this function load the specified config_file.
+
+=cut
+
+sub load
+{
+    my ($self) = @_ ;
+
+    unless (open(FP, $self->{config_file}))
+    {
+       return $self->error("can't load config_file $self->{config_file} : $!");
+    }
+    my $f=''; my $tmpbuffer;
+    while(read FP,$tmpbuffer,4096)
+    {
+       $f .= $tmpbuffer;
+    }
+    close(FP);
+
+    my $VAR1;
+
+    no strict; # I have no idea of the contents of the file
+    eval "$f" ;
+    use strict;
+
+    if ($f and $@) {
+       $self->load_old();
+       $self->save();
+       return $self->error("If you update from an old bweb install, your must reload this page and if it's fail again, you have to configure bweb again...") ;
+    }
+
+    foreach my $k (keys %$VAR1) {
+       $self->{$k} = $VAR1->{$k};
+    }
+
+    return 1;
+}
+
+=head1 FUNCTION
+
+    load_old - load old configuration format
+
+=cut
+
+sub load_old
+{
+    my ($self) = @_ ;
+
+    unless (open(FP, $self->{config_file}))
+    {
+       return $self->error("$self->{config_file} : $!");
+    }
+
+    while (my $line = <FP>)
+    {
+       chomp($line);
+       my ($k, $v) = split(/\s*=\s*/, $line, 2);
+       if ($k_re{$k}) {
+           $self->{$k} = $v;
+       }
+    }
+
+    close(FP);
+    return 1;
+}
+
+=head1 FUNCTION
+
+    save - save the current configuration to config_file
+
+=cut
+
+sub save
+{
+    my ($self) = @_ ;
+
+    if ($self->{ach_list}) {
+       # shortcut for display_begin
+       $self->{achs} = [ map {{ name => $_ }} 
+                         keys %{$self->{ach_list}}
+                       ];
+    }
+
+    unless (open(FP, ">$self->{config_file}"))
+    {
+       return $self->error("$self->{config_file} : $!\n" .
+                           "You must add this to your config file\n" 
+                           . Data::Dumper::Dumper($self));
+    }
+
+    print FP Data::Dumper::Dumper($self);
+    
+    close(FP);       
+    return 1;
+}
+
+=head1 FUNCTIONS
+    
+    edit, view, modify - html form ouput
+
+=cut
+
+sub edit
+{
+    my ($self) = @_ ;
+
+    $self->display($self, "config_edit.tpl");
+}
+
+sub view
+{
+    my ($self) = @_ ;
+    $self->display($self, "config_view.tpl");
+}
+
+sub modify
+{
+    my ($self) = @_;
+    
+    $self->{error} = '';
+    $self->{debug} = 0;
+
+    foreach my $k (CGI::param())
+    {
+       next unless (exists $k_re{$k}) ;
+       my $val = CGI::param($k);
+       if ($val =~ $k_re{$k}) {
+           $self->{$k} = $1;
+       } else {
+           $self->{error} .= "bad parameter : $k = [$val]";
+       }
+    }
+
+    $self->view();
+
+    if ($self->{error}) {      # an error as occured
+       $self->display($self, 'error.tpl');
+    } else {
+       $self->save();
+    }
+}
+
+1;
+
+################################################################
+
+package Bweb::Client;
+
+use base q/Bweb::Gui/;
+
+=head1 PACKAGE
+    
+    Bweb::Client - Bacula FD
+
+=head2 DESCRIPTION
+
+    this package is use to do all Client operations like, parse status etc...
+
+=head2 USAGE
+
+    $client = new Bweb::Client(name => 'zog-fd');
+    $client->status();            # do a 'status client=zog-fd'
+
+=cut
+
+=head1 FUNCTION
+
+    display_running_job - Html display of a running job
+
+=head2 DESCRIPTION
+
+    this function is used to display information about a current job
+
+=cut
+
+sub display_running_job
+{
+    my ($self, $conf, $jobid) = @_ ;
+
+    my $status = $self->status($conf);
+
+    if ($jobid) {
+       if ($status->{$jobid}) {
+           $self->display($status->{$jobid}, "client_job_status.tpl");
+       }
+    } else {
+       for my $id (keys %$status) {
+           $self->display($status->{$id}, "client_job_status.tpl");
+       }
+    }
+}
+
+=head1 FUNCTION
+
+    $client = new Bweb::Client(name => 'plume-fd');
+                               
+    $client->status($bweb);
+
+=head2 DESCRIPTION
+
+    dirty hack to parse "status client=xxx-fd"
+
+=head2 INPUT
+
+   JobId 105 Job Full_plume.2006-06-06_17.22.23 is running.
+       Backup Job started: 06-jun-06 17:22
+       Files=8,971 Bytes=194,484,132 Bytes/sec=7,480,158
+       Files Examined=10,697
+       Processing file: /home/eric/.openoffice.org2/user/config/standard.sod
+       SDReadSeqNo=5 fd=5
+   
+=head2 OUTPUT
+
+    $VAR1 = { 105 => {
+               JobName => Full_plume.2006-06-06_17.22.23,
+               JobId => 105,
+               Files => 8,971,
+               Bytes => 194,484,132,
+               ...
+              },
+             ...
+    };
+
+=cut
+
+sub status
+{
+    my ($self, $conf) = @_ ;
+
+    if (defined $self->{cur_jobs}) {
+       return $self->{cur_jobs} ;
+    }
+
+    my $arg = {};
+    my $b = new Bconsole(pref => $conf);
+    my $ret = $b->send_cmd("st client=$self->{name}");
+    my @param;
+    my $jobid;
+
+    for my $r (split(/\n/, $ret)) {
+       chomp($r);
+       $r =~ s/(^\s+|\s+$)//g;
+       if ($r =~ /JobId (\d+) Job (\S+)/) {
+           if ($jobid) {
+               $arg->{$jobid} = { @param, JobId => $jobid } ;
+           }
+
+           $jobid = $1;
+           @param = ( JobName => $2 );
+
+       } elsif ($r =~ /=.+=/) {
+           push @param, split(/\s+|\s*=\s*/, $r) ;
+
+       } elsif ($r =~ /=/) {   # one per line
+           push @param, split(/\s*=\s*/, $r) ;
+
+       } elsif ($r =~ /:/) {   # one per line
+           push @param, split(/\s*:\s*/, $r, 2) ;
+       }
+    }
+
+    if ($jobid and @param) {
+       $arg->{$jobid} = { @param,
+                          JobId => $jobid, 
+                          Client => $self->{name},
+                      } ;
+    }
+
+    $self->{cur_jobs} = $arg ;
+
+    return $arg;
+}
+1;
+
+################################################################
+
+package Bweb::Autochanger;
+
+use base q/Bweb::Gui/;
+
+=head1 PACKAGE
+    
+    Bweb::Autochanger - Object to manage Autochanger
+
+=head2 DESCRIPTION
+
+    this package will parse the mtx output and manage drives.
+
+=head2 USAGE
+
+    $auto = new Bweb::Autochanger(precmd => 'sudo');
+    or
+    $auto = new Bweb::Autochanger(precmd => 'ssh root@robot');
+                                  
+    $auto->status();
+
+    $auto->slot_is_full(10);
+    $auto->transfer(10, 11);
+
+=cut
+
+sub new
+{
+    my ($class, %arg) = @_;
+
+    my $self = bless {
+       name  => '',    # autochanger name
+       label => {},    # where are volume { label1 => 40, label2 => drive0 }
+       drive => [],    # drive use [ 'media1', 'empty', ..]
+       slot  => [],    # slot use [ undef, 'empty', 'empty', ..] no slot 0
+       io    => [],    # io slot number list [ 41, 42, 43...]
+       info  => {slot => 0,    # informations (slot, drive, io)
+                 io   => 0,
+                 drive=> 0,
+                },
+       mtxcmd => '/usr/sbin/mtx',
+       debug => 0,
+       device => '/dev/changer',
+       precmd => '',   # ssh command
+       bweb => undef,  # link to bacula web object (use for display) 
+    } ;
+
+    map { $self->{lc($_)} = $arg{$_} } keys %arg ;
+
+    return $self;
+}
+
+=head1 FUNCTION
+
+    status - parse the output of mtx status
+
+=head2 DESCRIPTION
+
+    this function will launch mtx status and parse the output. it will
+    give a perlish view of the autochanger content.
+
+    it uses ssh if the autochanger is on a other host.
+
+=cut
+
+sub status
+{
+    my ($self) = @_;
+    my @out = `$self->{precmd} $self->{mtxcmd} -f $self->{device} status` ;
+
+    # TODO : reset all infos
+    $self->{info}->{drive} = 0;
+    $self->{info}->{slot}  = 0;
+    $self->{info}->{io}    = 0;
+
+    #my @out = `cat /home/eric/travail/brestore/plume/mtx` ;
+
+#
+#  Storage Changer /dev/changer:2 Drives, 45 Slots ( 5 Import/Export )
+#Data Transfer Element 0:Full (Storage Element 1 Loaded):VolumeTag = 000000
+#Data Transfer Element 1:Empty
+#      Storage Element 1:Empty
+#      Storage Element 2:Full :VolumeTag=000002
+#      Storage Element 3:Empty
+#      Storage Element 4:Full :VolumeTag=000004
+#      Storage Element 5:Full :VolumeTag=000001
+#      Storage Element 6:Full :VolumeTag=000003
+#      Storage Element 7:Empty
+#      Storage Element 41 IMPORT/EXPORT:Empty
+#      Storage Element 41 IMPORT/EXPORT:Full :VolumeTag=000002
+#
+
+    for my $l (@out) {
+
+        #          Storage Element 7:Empty
+        #          Storage Element 2:Full :VolumeTag=000002
+       if ($l =~ /Storage Element (\d+):(Empty|Full)(\s+:VolumeTag=([\w\d]+))?/){
+
+           if ($2 eq 'Empty') {
+               $self->set_empty_slot($1);
+           } else {
+               $self->set_slot($1, $4);
+           }
+
+       } elsif ($l =~ /Data Transfer.+(\d+):(Full|Empty)(\s+.Storage Element (\d+) Loaded.(:VolumeTag = ([\w\d]+))?)?/) {
+
+           if ($2 eq 'Empty') {
+               $self->set_empty_drive($1);
+           } else {
+               $self->set_drive($1, $4, $6);
+           }
+
+       } elsif ($l =~ /Storage Element (\d+).+IMPORT\/EXPORT:(Empty|Full)( :VolumeTag=([\d\w]+))?/) 
+       {
+           if ($2 eq 'Empty') {
+               $self->set_empty_io($1);
+           } else {
+               $self->set_io($1, $4);
+           }
+
+#       Storage Changer /dev/changer:2 Drives, 30 Slots ( 1 Import/Export )
+
+       } elsif ($l =~ /Storage Changer .+:(\d+) Drives, (\d+) Slots/) {
+           $self->{info}->{drive} = $1;
+           $self->{info}->{slot} = $2;
+           if ($l =~ /(\d+)\s+Import/) {
+               $self->{info}->{io} = $1 ;
+           } else {
+               $self->{info}->{io} = 0;
+           }
+       } 
+    }
+
+    $self->debug($self) ;
+}
+
+sub is_slot_loaded
+{
+    my ($self, $slot) = @_;
+
+    # no barcodes
+    if ($self->{slot}->[$slot] eq 'loaded') {
+       return 1;
+    } 
+
+    my $label = $self->{slot}->[$slot] ;
+
+    return $self->is_media_loaded($label);
+}
+
+sub unload
+{
+    my ($self, $drive, $slot) = @_;
+
+    return 0 if (not defined $drive or $self->{drive}->[$drive] eq 'empty') ;
+    return 0 if     ($self->slot_is_full($slot)) ;
+
+    my $out = `$self->{precmd} $self->{mtxcmd} -f $self->{device} unload $slot $drive 2>&1`;
+    
+    if ($? == 0) {
+       my $content = $self->get_slot($slot);
+       print "content = $content<br/> $drive => $slot<br/>";
+       $self->set_empty_drive($drive);
+       $self->set_slot($slot, $content);
+       return 1;
+    } else {
+       $self->{error} = $out;
+       return 0;
+    }
+}
+
+# TODO: load/unload have to use mtx script from bacula
+sub load
+{
+    my ($self, $drive, $slot) = @_;
+
+    return 0 if (not defined $drive or $self->{drive}->[$drive] ne 'empty') ;
+    return 0 unless ($self->slot_is_full($slot)) ;
+
+    print "Loading drive $drive with slot $slot<br/>\n";
+    my $out = `$self->{precmd} $self->{mtxcmd} -f $self->{device} load $slot $drive 2>&1`;
+    
+    if ($? == 0) {
+       my $content = $self->get_slot($slot);
+       print "content = $content<br/> $slot => $drive<br/>";
+       $self->set_drive($drive, $slot, $content);
+       return 1;
+    } else {
+       $self->{error} = $out;
+       print $out;
+       return 0;
+    }
+}
+
+sub is_media_loaded
+{
+    my ($self, $media) = @_;
+
+    unless ($self->{label}->{$media}) {
+       return 0;
+    }
+
+    if ($self->{label}->{$media} =~ /drive\d+/) {
+       return 1;
+    }
+
+    return 0;
+}
+
+sub have_io
+{
+    my ($self) = @_;
+    return (defined $self->{info}->{io} and $self->{info}->{io} > 0);
+}
+
+sub set_io
+{
+    my ($self, $slot, $tag) = @_;
+    $self->{slot}->[$slot] = $tag || 'full';
+    push @{ $self->{io} }, $slot;
+
+    if ($tag) {
+       $self->{label}->{$tag} = $slot;
+    } 
+}
+
+sub set_empty_io
+{
+    my ($self, $slot) = @_;
+
+    push @{ $self->{io} }, $slot;
+
+    unless ($self->{slot}->[$slot]) {       # can be loaded (parse before) 
+       $self->{slot}->[$slot] = 'empty';
+    }
+}
+
+sub get_slot
+{
+    my ($self, $slot) = @_;
+    return $self->{slot}->[$slot];
+}
+
+sub set_slot
+{
+    my ($self, $slot, $tag) = @_;
+    $self->{slot}->[$slot] = $tag || 'full';
+
+    if ($tag) {
+       $self->{label}->{$tag} = $slot;
+    }
+}
+
+sub set_empty_slot
+{
+    my ($self, $slot) = @_;
+
+    unless ($self->{slot}->[$slot]) {       # can be loaded (parse before) 
+       $self->{slot}->[$slot] = 'empty';
+    }
+}
+
+sub set_empty_drive
+{
+    my ($self, $drive) = @_;
+    $self->{drive}->[$drive] = 'empty';
+}
+
+sub set_drive
+{
+    my ($self, $drive, $slot, $tag) = @_;
+    $self->{drive}->[$drive] = $tag || $slot;
+
+    $self->{slot}->[$slot] = $tag || 'loaded';
+
+    if ($tag) {
+       $self->{label}->{$tag} = "drive$drive";
+    }
+}
+
+sub slot_is_full
+{
+    my ($self, $slot) = @_;
+    
+    # slot don't exists => full
+    if (not defined $self->{slot}->[$slot]) {
+       return 0 ;
+    }
+
+    if ($self->{slot}->[$slot] eq 'empty') {
+       return 0;
+    }
+    return 1;                  # vol, full, loaded
+}
+
+sub slot_get_first_free
+{
+    my ($self) = @_;
+    for (my $slot=1; $slot < $self->{info}->{slot}; $slot++) {
+       return $slot unless ($self->slot_is_full($slot));
+    }
+}
+
+sub io_get_first_free
+{
+    my ($self) = @_;
+    
+    foreach my $slot (@{ $self->{io} }) {
+       return $slot unless ($self->slot_is_full($slot));       
+    }
+    return 0;
+}
+
+sub get_media_slot
+{
+    my ($self, $media) = @_;
+
+    return $self->{label}->{$media} ;    
+}
+
+sub have_media
+{
+    my ($self, $media) = @_;
+
+    return defined $self->{label}->{$media} ;    
+}
+
+sub send_to_io
+{
+    my ($self, $slot) = @_;
+
+    unless ($self->slot_is_full($slot)) {
+       print "Autochanger $self->{name} slot $slot is empty\n";
+       return 1;               # ok
+    }
+
+    # first, eject it
+    if ($self->is_slot_loaded($slot)) {
+       # bconsole->umount
+       # self->eject
+       print "Autochanger $self->{name} $slot is currently in use\n";
+       return 0;
+    }
+
+    # autochanger must have I/O
+    unless ($self->have_io()) {
+       print "Autochanger $self->{name} don't have I/O, you can take media yourself\n";
+       return 0;
+    }
+
+    my $dst = $self->io_get_first_free();
+
+    unless ($dst) {
+       print "Autochanger $self->{name} you must empty I/O first\n";
+    }
+
+    $self->transfer($slot, $dst);
+}
+
+sub transfer
+{
+    my ($self, $src, $dst) = @_ ;
+    if ($self->{debug}) {
+       print "<pre>$self->{precmd} $self->{mtxcmd} -f $self->{device} transfer $src $dst</pre>\n";
+    }
+    my $out = `$self->{precmd} $self->{mtxcmd} -f $self->{device} transfer $src $dst 2>&1`;
+    
+    if ($? == 0) {
+       my $content = $self->get_slot($src);
+       $self->{slot}->[$src] = 'empty';
+       $self->set_slot($dst, $content);
+       return 1;
+    } else {
+       $self->{error} = $out;
+       return 0;
+    }
+}
+
+sub get_drive_name
+{
+    my ($self, $index) = @_;
+    return $self->{drive_name}->[$index];
+}
+
+# TODO : do a tapeinfo request to get informations
+sub tapeinfo
+{
+    my ($self) = @_;
+}
+
+sub clear_io
+{
+    my ($self) = @_;
+
+    for my $slot (@{$self->{io}})
+    {
+       if ($self->is_slot_loaded($slot)) {
+           print "$slot is currently loaded\n";
+           next;
+       }
+
+       if ($self->slot_is_full($slot))
+       {
+           my $free = $self->slot_get_first_free() ;
+           print "move $slot to $free :\n";
+
+           if ($free) {
+               if ($self->transfer($slot, $free)) {
+                   print "<img src='/bweb/T.png' alt='ok'><br/>\n";
+               } else {
+                   print "<img src='/bweb/E.png' alt='ok' title='$self->{error}'><br/>\n";
+               }
+               
+           } else {
+               $self->{error} = "<img src='/bweb/E.png' alt='ok' title='E : Can t find free slot'><br/>\n";
+           }
+       }
+    }
+}
+
+# TODO : this is with mtx status output,
+# we can do an other function from bacula view (with StorageId)
+sub display_content
+{
+    my ($self) = @_;
+    my $bweb = $self->{bweb};
+
+    # $self->{label} => ('vol1', 'vol2', 'vol3', ..);
+    my $media_list = $bweb->dbh_join( keys %{ $self->{label} });
+
+    my $query="
+SELECT Media.VolumeName  AS volumename,
+       Media.VolStatus   AS volstatus,
+       Media.LastWritten AS lastwritten,
+       Media.VolBytes    AS volbytes,
+       Media.MediaType   AS mediatype,
+       Media.Slot        AS slot,
+       Media.InChanger   AS inchanger,
+       Pool.Name         AS name,
+       $bweb->{sql}->{FROM_UNIXTIME}(
+          $bweb->{sql}->{UNIX_TIMESTAMP}(Media.LastWritten) 
+        + $bweb->{sql}->{TO_SEC}(Media.VolRetention)
+       ) AS expire
+FROM Media 
+ INNER JOIN Pool USING (PoolId) 
+
+WHERE Media.VolumeName IN ($media_list)
+";
+
+    my $all = $bweb->dbh_selectall_hashref($query, 'volumename') ;
+
+    # TODO : verify slot and bacula slot
+    my $param = [];
+    my @to_update;
+
+    for (my $slot=1; $slot <= $self->{info}->{slot} ; $slot++) {
+
+       if ($self->slot_is_full($slot)) {
+
+           my $vol = $self->{slot}->[$slot];
+           if (defined $all->{$vol}) {    # TODO : autochanger without barcodes 
+
+               my $bslot = $all->{$vol}->{slot} ;
+               my $inchanger = $all->{$vol}->{inchanger};
+
+               # if bacula slot or inchanger flag is bad, we display a message
+               if ($bslot != $slot or !$inchanger) {
+                   push @to_update, $slot;
+               }
+               
+               $all->{$vol}->{realslot} = $slot;
+
+               push @{ $param }, $all->{$vol};
+
+           } else {            # empty or no label
+               push @{ $param }, {realslot => $slot,
+                                  volstatus => 'Unknow',
+                                  volumename => $self->{slot}->[$slot]} ;
+           }
+       } else {                # empty
+           push @{ $param }, {realslot => $slot, volumename => 'empty'} ;
+       }
+    }
+
+    my $i=0; my $drives = [] ;
+    foreach my $d (@{ $self->{drive} }) {
+       $drives->[$i] = { index => $i,
+                         load  => $self->{drive}->[$i],
+                         name  => $self->{drive_name}->[$i],
+                     };
+       $i++;
+    }
+
+    $bweb->display({ Name   => $self->{name},
+                    nb_drive => $self->{info}->{drive},
+                    nb_io => $self->{info}->{io},
+                    Drives => $drives,
+                    Slots  => $param,
+                    Update => scalar(@to_update) },
+                  'ach_content.tpl');
+
+}
+
+1;
+
+
+################################################################
+
+package Bweb;
+
+use base q/Bweb::Gui/;
+
+=head1 PACKAGE
+
+    Bweb - main Bweb package
+
+=head2
+
+    this package is use to compute and display informations
+
+=cut
+
+use DBI;
+use POSIX qw/strftime/;
+
+our $config_file='/etc/bacula/bweb.conf';
+
+our $cur_id=0;
+
+=head1 VARIABLE
+
+    %sql_func - hash to make query mysql/postgresql compliant
+
+=cut
+
+our %sql_func = ( 
+         Pg => { 
+             UNIX_TIMESTAMP => '',
+             FROM_UNIXTIME => '',
+             TO_SEC => " interval '1 second' * ",
+             SEC_TO_INT => "SEC_TO_INT",
+             SEC_TO_TIME => '',
+             MATCH => " ~ ",
+             STARTTIME_DAY  => " date_trunc('day', Job.StartTime) ",
+             STARTTIME_HOUR => " date_trunc('hour', Job.StartTime) ",
+             STARTTIME_MONTH  => " date_trunc('month', Job.StartTime) ",
+             STARTTIME_PHOUR=> " date_part('hour', Job.StartTime) ",
+             STARTTIME_PDAY => " date_part('day', Job.StartTime) ",
+             STARTTIME_PMONTH => " date_part('month', Job.StartTime) ",
+         },
+         mysql => {
+             UNIX_TIMESTAMP => 'UNIX_TIMESTAMP',
+             FROM_UNIXTIME => 'FROM_UNIXTIME',
+             SEC_TO_INT => '',
+             TO_SEC => '',
+             SEC_TO_TIME => 'SEC_TO_TIME',
+             MATCH => " REGEXP ",
+             STARTTIME_DAY  => " DATE_FORMAT(StartTime, '%Y-%m-%d') ",
+             STARTTIME_HOUR => " DATE_FORMAT(StartTime, '%Y-%m-%d %H') ",
+             STARTTIME_MONTH => " DATE_FORMAT(StartTime, '%Y-%m') ",
+             STARTTIME_PHOUR=> " DATE_FORMAT(StartTime, '%H') ",
+             STARTTIME_PDAY => " DATE_FORMAT(StartTime, '%d') ",
+             STARTTIME_PMONTH => " DATE_FORMAT(StartTime, '%m') ",
+         },
+        );
+
+sub dbh_selectall_arrayref
+{
+    my ($self, $query) = @_;
+    $self->connect_db();
+    $self->debug($query);
+    return $self->{dbh}->selectall_arrayref($query);
+}
+
+sub dbh_join
+{
+    my ($self, @what) = @_;
+    return join(',', $self->dbh_quote(@what)) ;
+}
+
+sub dbh_quote
+{
+    my ($self, @what) = @_;
+
+    $self->connect_db();
+    if (wantarray) {
+       return map { $self->{dbh}->quote($_) } @what;
+    } else {
+       return $self->{dbh}->quote($what[0]) ;
+    }
+}
+
+sub dbh_do
+{
+    my ($self, $query) = @_ ; 
+    $self->connect_db();
+    $self->debug($query);
+    return $self->{dbh}->do($query);
+}
+
+sub dbh_selectall_hashref
+{
+    my ($self, $query, $join) = @_;
+    
+    $self->connect_db();
+    $self->debug($query);
+    return $self->{dbh}->selectall_hashref($query, $join) ;
+}
+
+sub dbh_selectrow_hashref
+{
+    my ($self, $query) = @_;
+    
+    $self->connect_db();
+    $self->debug($query);
+    return $self->{dbh}->selectrow_hashref($query) ;
+}
+
+# display Mb/Gb/Kb
+sub human_size
+{
+    my @unit = qw(b Kb Mb Gb Tb);
+    my $val = shift || 0;
+    my $i=0;
+    my $format = '%i %s';
+    while ($val / 1024 > 1) {
+       $i++;
+       $val /= 1024;
+    }
+    $format = ($i>0)?'%0.1f %s':'%i %s';
+    return sprintf($format, $val, $unit[$i]);
+}
+
+# display Day, Hour, Year
+sub human_sec
+{
+    use integer;
+
+    my $val = shift;
+    $val /= 60;                        # sec -> min
+
+    if ($val / 60 <= 1) {
+       return "$val mins";
+    } 
+
+    $val /= 60;                        # min -> hour
+    if ($val / 24 <= 1) {
+       return "$val hours";
+    } 
+
+    $val /= 24;                        # hour -> day
+    if ($val / 365 < 2) {
+       return "$val days";
+    } 
+
+    $val /= 365 ;              # day -> year
+
+    return "$val years";   
+}
+
+# get Day, Hour, Year
+sub from_human_sec
+{
+    use integer;
+
+    my $val = shift;
+    unless ($val =~ /^\s*(\d+)\s*(\w)\w*\s*$/) {
+       return 0;
+    }
+
+    my %times = ( m   => 60,
+                 h   => 60*60,
+                 d   => 60*60*24,
+                 m   => 60*60*24*31,
+                 y   => 60*60*24*365,
+                 );
+    my $mult = $times{$2} || 0;
+
+    return $1 * $mult;   
+}
+
+
+sub connect_db
+{
+    my ($self) = @_;
+
+    unless ($self->{dbh}) {
+       $self->{dbh} = DBI->connect($self->{info}->{dbi}, 
+                                   $self->{info}->{user},
+                                   $self->{info}->{password});
+
+       $self->error("Can't connect to your database:\n$DBI::errstr\n")
+           unless ($self->{dbh});
+
+       $self->{dbh}->{FetchHashKeyName} = 'NAME_lc';
+
+       if ($self->{info}->{dbi} =~ /^dbi:Pg/i) {
+           $self->{dbh}->do("SET datestyle TO 'ISO, YMD'");
+       }
+    }
+}
+
+sub new
+{
+    my ($class, %arg) = @_;
+    my $self = bless { 
+       dbh => undef,           # connect_db();
+       info => {
+           dbi   => '', # DBI:Pg:database=bacula;host=127.0.0.1
+           user  => 'bacula',
+           password => 'test', 
+       },
+    } ;
+
+    map { $self->{lc($_)} = $arg{$_} } keys %arg ;
+
+    if ($self->{info}->{dbi} =~ /DBI:(\w+):/i) {
+       $self->{sql} = $sql_func{$1};
+    }
+
+    $self->{debug} = $self->{info}->{debug};
+    $Bweb::Gui::template_dir = $self->{info}->{template_dir};
+
+    return $self;
+}
+
+sub display_begin
+{
+    my ($self) = @_;
+    $self->display($self->{info}, "begin.tpl");
+}
+
+sub display_end
+{
+    my ($self) = @_;
+    $self->display($self->{info}, "end.tpl");
+}
+
+sub display_clients
+{
+    my ($self) = @_;
+
+    my $where='';
+    my $arg = $self->get_form("client", "qre_client");
+
+    if ($arg->{qre_client}) {
+       $where = "WHERE Name $self->{sql}->{MATCH} $arg->{qre_client} ";
+    } elsif ($arg->{client}) {
+       $where = "WHERE Name = '$arg->{client}' ";
+    }
+
+    my $query = "
+SELECT Name   AS name,
+       Uname  AS uname,
+       AutoPrune AS autoprune,
+       FileRetention AS fileretention,
+       JobRetention  AS jobretention
+FROM Client
+$where
+";
+
+    my $all = $self->dbh_selectall_hashref($query, 'name') ;
+
+    my $dsp = { ID => $cur_id++,
+               clients => [ values %$all] };
+
+    $self->display($dsp, "client_list.tpl") ;
+}
+
+sub get_limit
+{
+    my ($self, %arg) = @_;
+
+    my $limit = '';
+    my $label = '';
+
+    if ($arg{age}) {
+       $limit = 
+  "AND $self->{sql}->{UNIX_TIMESTAMP}(EndTime) 
+         > 
+       ( $self->{sql}->{UNIX_TIMESTAMP}(NOW()) 
+         - 
+         $self->{sql}->{TO_SEC}($arg{age})
+       )" ;
+
+       $label = "last " . human_sec($arg{age});
+    }
+
+    if ($arg{groupby}) {
+       $limit .= " GROUP BY $arg{groupby} ";
+    }
+
+    if ($arg{order}) {
+       $limit .= " ORDER BY $arg{order} ";
+    }
+
+    if ($arg{limit}) {
+       $limit .= " LIMIT $arg{limit} ";
+       $label .= " limited to $arg{limit}";
+    }
+
+    if ($arg{offset}) {
+       $limit .= " OFFSET $arg{offset} ";
+       $label .= " with $arg{offset} offset ";
+    }
+
+    unless ($label) {
+       $label = 'no filter';
+    }
+
+    return ($limit, $label);
+}
+
+=head1 FUNCTION
+
+    $bweb->get_form(...) - Get useful stuff
+
+=head2 DESCRIPTION
+
+    This function get and check parameters against regexp.
+    
+    If word begin with 'q', the return will be quoted or join quoted
+    if it's end with 's'.
+    
+
+=head2 EXAMPLE
+
+    $bweb->get_form('jobid', 'qclient', 'qpools') ;
+
+    { jobid    => 12,
+      qclient  => 'plume-fd',
+      qpools   => "'plume-fd', 'test-fd', '...'",
+    }
+
+=cut
+
+sub get_form
+{
+    my ($self, @what) = @_;
+    my %what = map { $_ => 1 } @what;
+    my %ret;
+
+    my %opt_i = (
+                limit  => 100,
+                cost   =>  10,
+                offset =>   0,
+                width  => 640,
+                height => 480,
+                jobid  =>   0,
+                slot   =>   0,
+                drive  =>   0,
+                priority => 10,
+                age    => 60*60*24*7,
+                days   => 1,
+                maxvoljobs  => 0,
+                maxvolbytes => 0,
+                maxvolfiles => 0,
+                );
+
+    my %opt_ss =(              # string with space
+                job     => 1,
+                storage => 1,
+                );
+    my %opt_s = (              # default to ''
+                ach    => 1,
+                status => 1,
+                volstatus => 1,
+                 inchanger => 1,
+                 client => 1,
+                level  => 1,
+                pool   => 1,
+                media  => 1,
+                 ach    => 1,
+                 jobtype=> 1,
+                graph  => 1,
+                 gtype  => 1,
+                 type   => 1,
+                poolrecycle => 1,
+                replace => 1,
+                );
+    my %opt_p = (              # option with path
+                fileset=> 1,
+                mtxcmd => 1,
+                precmd => 1,
+                device => 1,
+                where  => 1,
+                );
+
+    my %opt_d = (              # option with date
+                voluseduration=> 1,
+                volretention => 1,
+               );
+
+    foreach my $i (@what) {
+       if (exists $opt_i{$i}) {# integer param
+           my $value = CGI::param($i) || $opt_i{$i} ;
+           if ($value =~ /^(\d+)$/) {
+               $ret{$i} = $1;
+           }
+       } elsif ($opt_s{$i}) {  # simple string param
+           my $value = CGI::param($i) || '';
+           if ($value =~ /^([\w\d\.-]+)$/) {
+               $ret{$i} = $1;
+           }
+       } elsif ($opt_ss{$i}) { # simple string param (with space)
+           my $value = CGI::param($i) || '';
+           if ($value =~ /^([\w\d\.\-\s]+)$/) {
+               $ret{$i} = $1;
+           }
+       } elsif ($i =~ /^j(\w+)s$/) { # quote join args
+           my @value = grep { ! /^\s*$/ } CGI::param($1) ;
+           if (@value) {
+               $ret{$i} = $self->dbh_join(@value) ;
+           }
+
+       } elsif ($i =~ /^q(\w+[^s])$/) { # 'arg1'
+           my $value = CGI::param($1) ;
+           if ($value) {
+               $ret{$i} = $self->dbh_quote($value);
+           }
+
+       } elsif ($i =~ /^q(\w+)s$/) { #[ 'arg1', 'arg2']
+           $ret{$i} = [ map { { name => $self->dbh_quote($_) } } 
+                                          grep { ! /^\s*$/ } CGI::param($1) ];
+       } elsif (exists $opt_p{$i}) {
+           my $value = CGI::param($i) || '';
+           if ($value =~ /^([\w\d\.\/\s:\@\-]+)$/) {
+               $ret{$i} = $1;
+           }
+       } elsif (exists $opt_d{$i}) {
+           my $value = CGI::param($i) || '';
+           if ($value =~ /^\s*(\d+\s+\w+)$/) {
+               $ret{$i} = $1;
+           }
+       }
+    }
+
+    if ($what{slots}) {
+       foreach my $s (CGI::param('slot')) {
+           if ($s =~ /^(\d+)$/) {
+               push @{$ret{slots}}, $s;
+           }
+       }
+    }
+
+    if ($what{when}) {
+       my $when = CGI::param('when') || '';
+       if ($when =~ /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})$/) {
+           $ret{when} = $1;
+       }
+    }
+
+    if ($what{db_clients}) {
+       my $query = "
+SELECT Client.Name as clientname
+FROM Client
+";
+
+       my $clients = $self->dbh_selectall_hashref($query, 'clientname');
+       $ret{db_clients} = [sort {$a->{clientname} cmp $b->{clientname} } 
+                             values %$clients] ;
+    }
+
+    if ($what{db_mediatypes}) {
+       my $query = "
+SELECT MediaType as mediatype
+FROM MediaType
+";
+
+       my $medias = $self->dbh_selectall_hashref($query, 'mediatype');
+       $ret{db_mediatypes} = [sort {$a->{mediatype} cmp $b->{mediatype} } 
+                                 values %$medias] ;
+    }
+
+    if ($what{db_locations}) {
+       my $query = "
+SELECT Location as location, Cost as cost FROM Location
+";
+       my $loc = $self->dbh_selectall_hashref($query, 'location');
+       $ret{db_locations} = [ sort { $a->{location} 
+                                     cmp 
+                                     $b->{location} 
+                                 } values %$loc ];
+    }
+
+    if ($what{db_pools}) {
+       my $query = "SELECT Name as name FROM Pool";
+
+       my $all = $self->dbh_selectall_hashref($query, 'name') ;
+       $ret{db_pools} = [ sort { $a->{name} cmp $b->{name} } values %$all ];
+    }
+
+    if ($what{db_filesets}) {
+       my $query = "
+SELECT FileSet.FileSet AS fileset 
+FROM FileSet
+";
+
+       my $filesets = $self->dbh_selectall_hashref($query, 'fileset');
+
+       $ret{db_filesets} = [sort {lc($a->{fileset}) cmp lc($b->{fileset}) } 
+                              values %$filesets] ;
+    }
+
+    if ($what{db_jobnames}) {
+       my $query = "
+SELECT DISTINCT Job.Name AS jobname 
+FROM Job
+";
+
+       my $jobnames = $self->dbh_selectall_hashref($query, 'jobname');
+
+       $ret{db_jobnames} = [sort {lc($a->{jobname}) cmp lc($b->{jobname}) } 
+                              values %$jobnames] ;
+    }
+
+    if ($what{db_devices}) {
+       my $query = "
+SELECT Device.Name AS name
+FROM Device
+";
+
+       my $devices = $self->dbh_selectall_hashref($query, 'name');
+
+       $ret{db_devices} = [sort {lc($a->{name}) cmp lc($b->{name}) } 
+                              values %$devices] ;
+    }
+
+    return \%ret;
+}
+
+sub display_graph
+{
+    my ($self) = @_;
+
+    my $fields = $self->get_form(qw/age level status clients filesets 
+                                    graph gtype type
+                                   db_clients limit db_filesets width height
+                                   qclients qfilesets qjobnames db_jobnames/);
+                               
+
+    my $url = CGI::url(-full => 0,
+                      -base => 0,
+                      -query => 1);
+    $url =~ s/^.+?\?//;        # http://path/to/bweb.pl?arg => arg
+
+# this organisation is to keep user choice between 2 click
+# TODO : fileset and client selection doesn't work
+
+    $self->display({
+       url => $url,
+       %$fields,
+    }, "graph.tpl")
+
+}
+
+sub display_client_job
+{
+    my ($self, %arg) = @_ ;
+
+    $arg{order} = ' Job.JobId DESC ';
+    my ($limit, $label) = $self->get_limit(%arg);
+
+    my $clientname = $self->dbh_quote($arg{clientname});
+
+    my $query="
+SELECT DISTINCT Job.JobId       AS jobid,
+               Job.Name        AS jobname,
+                FileSet.FileSet AS fileset,
+                Level           AS level,
+                StartTime       AS starttime,
+                JobFiles        AS jobfiles, 
+                JobBytes        AS jobbytes,
+                JobStatus       AS jobstatus,
+               JobErrors       AS joberrors
+
+ FROM Client,Job,FileSet
+ WHERE Client.Name=$clientname
+ AND Client.ClientId=Job.ClientId
+ AND Job.FileSetId=FileSet.FileSetId
+ $limit
+";
+
+    my $all = $self->dbh_selectall_hashref($query, 'jobid') ;
+
+    $self->display({ clientname => $arg{clientname},
+                    Filter => $label,
+                    ID => $cur_id++,
+                    Jobs => [ values %$all ],
+                  },
+                  "display_client_job.tpl") ;
+}
+
+sub get_selected_media_location
+{
+    my ($self) = @_ ;
+
+    my $medias = $self->get_form('jmedias');
+
+    unless ($medias->{jmedias}) {
+       return undef;
+    }
+
+    my $query = "
+SELECT Media.VolumeName AS volumename, Location.Location AS location
+FROM Media LEFT JOIN Location ON (Media.LocationId = Location.LocationId)
+WHERE Media.VolumeName IN ($medias->{jmedias})
+";
+
+    my $all = $self->dbh_selectall_hashref($query, 'volumename') ;
+  
+    # { 'vol1' => { [volumename => 'vol1', location => 'ici'],
+    #               ..
+    #             }
+    # }
+    return $all;
+}
+
+sub move_media
+{
+    my ($self) = @_ ;
+
+    my $medias = $self->get_selected_media_location();
+
+    unless ($medias) {
+       return ;
+    }
+    
+    my $elt = $self->get_form('db_locations');
+
+    $self->display({ ID => $cur_id++,
+                    %$elt,     # db_locations
+                    medias => [ 
+            sort { $a->{volumename} cmp $b->{volumename} } values %$medias
+                              ],
+                    },
+                  "move_media.tpl");
+}
+
+sub help_extern
+{
+    my ($self) = @_ ;
+
+    my $elt = $self->get_form(qw/db_pools db_mediatypes db_locations/) ;
+    $self->debug($elt);
+    $self->display($elt, "help_extern.tpl");
+}
+
+sub help_extern_compute
+{
+    my ($self) = @_;
+
+    my $number = CGI::param('limit') || '' ;
+    unless ($number =~ /^(\d+)$/) {
+       return $self->error("Bad arg number : $number ");
+    }
+
+    my ($sql, undef) = $self->get_param('pools', 
+                                       'locations', 'mediatypes');
+
+    my $query = "
+SELECT Media.VolumeName  AS volumename,
+       Media.VolStatus   AS volstatus,
+       Media.LastWritten AS lastwritten,
+       Media.MediaType   AS mediatype,
+       Media.VolMounts   AS volmounts,
+       Pool.Name         AS name,
+       Media.Recycle     AS recycle,
+       $self->{sql}->{FROM_UNIXTIME}(
+          $self->{sql}->{UNIX_TIMESTAMP}(Media.LastWritten) 
+        + $self->{sql}->{TO_SEC}(Media.VolRetention)
+       ) AS expire
+FROM Media 
+ INNER JOIN Pool     ON (Pool.PoolId = Media.PoolId)
+ LEFT  JOIN Location ON (Media.LocationId = Location.LocationId)
+
+WHERE Media.InChanger = 1
+  AND Media.VolStatus IN ('Disabled', 'Error', 'Full')
+  $sql
+ORDER BY expire DESC, recycle, Media.VolMounts DESC
+LIMIT $number
+" ;
+    
+    my $all = $self->dbh_selectall_hashref($query, 'volumename') ;
+
+    $self->display({ Medias => [ values %$all ] },
+                  "help_extern_compute.tpl");
+}
+
+sub help_intern
+{
+    my ($self) = @_ ;
+
+    my $param = $self->get_form(qw/db_locations db_pools db_mediatypes/) ;
+    $self->display($param, "help_intern.tpl");
+}
+
+sub help_intern_compute
+{
+    my ($self) = @_;
+
+    my $number = CGI::param('limit') || '' ;
+    unless ($number =~ /^(\d+)$/) {
+       return $self->error("Bad arg number : $number ");
+    }
+
+    my ($sql, undef) = $self->get_param('pools', 'locations', 'mediatypes');
+
+    if (CGI::param('expired')) {
+       $sql = "
+AND (    $self->{sql}->{UNIX_TIMESTAMP}(Media.LastWritten) 
+       + $self->{sql}->{TO_SEC}(Media.VolRetention)
+    ) < NOW()
+ " . $sql ;
+    }
+
+    my $query = "
+SELECT Media.VolumeName  AS volumename,
+       Media.VolStatus   AS volstatus,
+       Media.LastWritten AS lastwritten,
+       Media.MediaType   AS mediatype,
+       Media.VolMounts   AS volmounts,
+       Pool.Name         AS name,
+       $self->{sql}->{FROM_UNIXTIME}(
+          $self->{sql}->{UNIX_TIMESTAMP}(Media.LastWritten) 
+        + $self->{sql}->{TO_SEC}(Media.VolRetention)
+       ) AS expire
+FROM Media 
+ INNER JOIN Pool ON (Pool.PoolId = Media.PoolId) 
+ LEFT  JOIN Location ON (Location.LocationId = Media.LocationId)
+
+WHERE Media.InChanger <> 1
+  AND Media.VolStatus IN ('Purged', 'Full', 'Append')
+  AND Media.Recycle = 1
+  $sql
+ORDER BY Media.VolUseDuration DESC, Media.VolMounts ASC, expire ASC 
+LIMIT $number
+" ;
+    
+    my $all = $self->dbh_selectall_hashref($query, 'volumename') ;
+
+    $self->display({ Medias => [ values %$all ] },
+                  "help_intern_compute.tpl");
+
+}
+
+sub display_general
+{
+    my ($self, %arg) = @_ ;
+
+    my ($limit, $label) = $self->get_limit(%arg);
+
+    my $query = "
+SELECT
+    (SELECT count(Pool.PoolId)   FROM Pool)   AS nb_pool,
+    (SELECT count(Media.MediaId) FROM Media)  AS nb_media,
+    (SELECT count(Job.JobId)     FROM Job)    AS nb_job,
+    (SELECT sum(VolBytes)        FROM Media)  AS nb_bytes,
+    (SELECT count(Job.JobId)
+      FROM Job
+      WHERE Job.JobStatus IN ('E','e','f','A')
+      $limit
+    )                                         AS nb_err,
+    (SELECT count(Client.ClientId) FROM Client) AS nb_client
+";
+
+    my $row = $self->dbh_selectrow_hashref($query) ;
+
+    $row->{nb_bytes} = human_size($row->{nb_bytes});
+
+    $row->{db_size} = '???';
+    $row->{label} = $label;
+
+    $self->display($row, "general.tpl");
+}
+
+sub get_param
+{
+    my ($self, @what) = @_ ;
+    my %elt = map { $_ => 1 } @what;
+    my %ret;
+
+    my $limit = '';
+
+    if ($elt{clients}) {
+       my @clients = grep { ! /^\s*$/ } CGI::param('client');
+       if (@clients) {
+           $ret{clients} = \@clients;
+           my $str = $self->dbh_join(@clients);
+           $limit .= "AND Client.Name IN ($str) ";
+       }
+    }
+
+    if ($elt{filesets}) {
+       my @filesets = grep { ! /^\s*$/ } CGI::param('fileset');
+       if (@filesets) {
+           $ret{filesets} = \@filesets;
+           my $str = $self->dbh_join(@filesets);
+           $limit .= "AND FileSet.FileSet IN ($str) ";
+       }
+    }
+
+    if ($elt{mediatypes}) {
+       my @medias = grep { ! /^\s*$/ } CGI::param('mediatype');
+       if (@medias) {
+           $ret{mediatypes} = \@medias;
+           my $str = $self->dbh_join(@medias);
+           $limit .= "AND Media.MediaType IN ($str) ";
+       }
+    }
+
+    if ($elt{client}) {
+       my $client = CGI::param('client');
+       $ret{client} = $client;
+       $client = $self->dbh_join($client);
+       $limit .= "AND Client.Name = $client ";
+    }
+
+    if ($elt{level}) {
+       my $level = CGI::param('level') || '';
+       if ($level =~ /^(\w)$/) {
+           $ret{level} = $1;
+           $limit .= "AND Job.Level = '$1' ";
+       }
+    }
+
+    if ($elt{jobid}) {
+       my $jobid = CGI::param('jobid') || '';
+
+       if ($jobid =~ /^(\d+)$/) {
+           $ret{jobid} = $1;
+           $limit .= "AND Job.JobId = '$1' ";
+       }
+    }
+
+    if ($elt{status}) {
+       my $status = CGI::param('status') || '';
+       if ($status =~ /^(\w)$/) {
+           $ret{status} = $1;
+           if ($1 eq 'f') {
+               $limit .= "AND Job.JobStatus IN ('f','E') ";            
+           } else {
+               $limit .= "AND Job.JobStatus = '$1' ";          
+           }
+       }
+    }
+
+    if ($elt{volstatus}) {
+       my $status = CGI::param('volstatus') || '';
+       if ($status =~ /^(\w+)$/) {
+           $ret{status} = $1;
+           $limit .= "AND Media.VolStatus = '$1' ";            
+       }
+    }
+
+    if ($elt{locations}) {
+       my @location = grep { ! /^\s*$/ } CGI::param('location') ;
+       if (@location) {
+           $ret{locations} = \@location;           
+           my $str = $self->dbh_join(@location);
+           $limit .= "AND Location.Location IN ($str) ";
+       }
+    }
+
+    if ($elt{pools}) {
+       my @pool = grep { ! /^\s*$/ } CGI::param('pool') ;
+       if (@pool) {
+           $ret{pools} = \@pool; 
+           my $str = $self->dbh_join(@pool);
+           $limit .= "AND Pool.Name IN ($str) ";
+       }
+    }
+
+    if ($elt{location}) {
+       my $location = CGI::param('location') || '';
+       if ($location) {
+           $ret{location} = $location;
+           $location = $self->dbh_quote($location);
+           $limit .= "AND Location.Location = $location ";
+       }
+    }
+
+    if ($elt{pool}) {
+       my $pool = CGI::param('pool') || '';
+       if ($pool) {
+           $ret{pool} = $pool;
+           $pool = $self->dbh_quote($pool);
+           $limit .= "AND Pool.Name = $pool ";
+       }
+    }
+
+    if ($elt{jobtype}) {
+       my $jobtype = CGI::param('jobtype') || '';
+       if ($jobtype =~ /^(\w)$/) {
+           $ret{jobtype} = $1;
+           $limit .= "AND Job.Type = '$1' ";
+       }
+    }
+
+    return ($limit, %ret);
+}
+
+=head1
+
+    get last backup
+
+=cut 
+
+sub display_job
+{
+    my ($self, %arg) = @_ ;
+
+    $arg{order} = ' Job.JobId DESC ';
+
+    my ($limit, $label) = $self->get_limit(%arg);
+    my ($where, undef) = $self->get_param('clients',
+                                         'level',
+                                         'filesets',
+                                         'jobtype',
+                                         'pools',
+                                         'jobid',
+                                         'status');
+
+    my $query="
+SELECT  Job.JobId       AS jobid,
+        Client.Name     AS client,
+        FileSet.FileSet AS fileset,
+       Job.Name        AS jobname,
+        Level           AS level,
+        StartTime       AS starttime,
+        Pool.Name       AS poolname,
+        JobFiles        AS jobfiles, 
+        JobBytes        AS jobbytes,
+       JobStatus       AS jobstatus,
+     $self->{sql}->{SEC_TO_TIME}(  $self->{sql}->{UNIX_TIMESTAMP}(EndTime)  
+                                 - $self->{sql}->{UNIX_TIMESTAMP}(StartTime)) 
+                        AS duration,
+
+        JobErrors      AS joberrors
+
+ FROM Client, 
+      Job LEFT JOIN Pool     ON (Job.PoolId    = Pool.PoolId)
+          LEFT JOIN FileSet  ON (Job.FileSetId = FileSet.FileSetId)
+ WHERE Client.ClientId=Job.ClientId
+   AND Job.JobStatus != 'R'
+ $where
+ $limit
+";
+
+    my $all = $self->dbh_selectall_hashref($query, 'jobid') ;
+
+    $self->display({ Filter => $label,
+                    ID => $cur_id++,
+                    Jobs => 
+                          [ 
+                            sort { $a->{jobid} <=>  $b->{jobid} } 
+                                       values %$all 
+                            ],
+                  },
+                  "display_job.tpl");
+}
+
+# display job informations
+sub display_job_zoom
+{
+    my ($self, $jobid) = @_ ;
+
+    $jobid = $self->dbh_quote($jobid);
+    
+    my $query="
+SELECT DISTINCT Job.JobId       AS jobid,
+                Client.Name     AS client,
+               Job.Name        AS jobname,
+                FileSet.FileSet AS fileset,
+                Level           AS level,
+               Pool.Name       AS poolname,
+                StartTime       AS starttime,
+                JobFiles        AS jobfiles, 
+                JobBytes        AS jobbytes,
+               JobStatus       AS jobstatus,
+                JobErrors       AS joberrors,
+                $self->{sql}->{SEC_TO_TIME}(  $self->{sql}->{UNIX_TIMESTAMP}(EndTime)  
+                                            - $self->{sql}->{UNIX_TIMESTAMP}(StartTime)) AS duration
+
+ FROM Client,
+      Job LEFT JOIN FileSet ON (Job.FileSetId = FileSet.FileSetId)
+          LEFT JOIN Pool    ON (Job.PoolId    = Pool.PoolId)
+ WHERE Client.ClientId=Job.ClientId
+ AND Job.JobId = $jobid
+";
+
+    my $row = $self->dbh_selectrow_hashref($query) ;
+
+    # display all volumes associate with this job
+    $query="
+SELECT Media.VolumeName as volumename
+FROM Job,Media,JobMedia
+WHERE Job.JobId = $jobid
+ AND JobMedia.JobId=Job.JobId 
+ AND JobMedia.MediaId=Media.MediaId
+";
+
+    my $all = $self->dbh_selectall_hashref($query, 'volumename');
+
+    $row->{volumes} = [ values %$all ] ;
+
+    $self->display($row, "display_job_zoom.tpl");
+}
+
+sub display_media
+{
+    my ($self) = @_ ;
+
+    my ($where, %elt) = $self->get_param('pools',
+                                        'mediatypes',
+                                        'volstatus',
+                                        'locations');
+
+    my $arg = $self->get_form('jmedias', 'qre_media');
+
+    if ($arg->{jmedias}) {
+       $where = "AND Media.VolumeName IN ($arg->{jmedias}) $where"; 
+    }
+    if ($arg->{qre_media}) {
+       $where = "AND Media.VolumeName $self->{sql}->{MATCH} $arg->{qre_media} $where"; 
+    }
+
+    my $query="
+SELECT Media.VolumeName  AS volumename, 
+       Media.VolBytes    AS volbytes,
+       Media.VolStatus   AS volstatus,
+       Media.MediaType   AS mediatype,
+       Media.InChanger   AS online,
+       Media.LastWritten AS lastwritten,
+       Location.Location AS location,
+       (volbytes*100/COALESCE(media_avg_size.size,-1))  AS volusage,
+       Pool.Name         AS poolname,
+       $self->{sql}->{FROM_UNIXTIME}(
+          $self->{sql}->{UNIX_TIMESTAMP}(Media.LastWritten) 
+        + $self->{sql}->{TO_SEC}(Media.VolRetention)
+       ) AS expire
+FROM      Pool, Media 
+LEFT JOIN Location ON (Media.LocationId = Location.LocationId)
+LEFT JOIN (SELECT avg(Media.VolBytes) AS size,
+                  Media.MediaType     AS MediaType
+           FROM Media 
+          WHERE Media.VolStatus = 'Full' 
+          GROUP BY Media.MediaType
+           ) AS media_avg_size ON (Media.MediaType = media_avg_size.MediaType)
+
+WHERE Media.PoolId=Pool.PoolId
+$where
+";
+
+    my $all = $self->dbh_selectall_hashref($query, 'volumename') ;
+
+    $self->display({ ID => $cur_id++,
+                    Pool => $elt{pool},
+                    Location => $elt{location},
+                    Medias => [ values %$all ]
+                  },
+                  "display_media.tpl");
+}
+
+sub display_medias
+{
+    my ($self) = @_ ;
+
+    my $pool = $self->get_form('db_pools');
+    
+    foreach my $name (@{ $pool->{db_pools} }) {
+       CGI::param('pool', $name->{name});
+       $self->display_media();
+    }
+}
+
+sub display_media_zoom
+{
+    my ($self) = @_ ;
+
+    my $medias = $self->get_form('jmedias');
+    
+    unless ($medias->{jmedias}) {
+       return $self->error("Can't get media selection");
+    }
+    
+    my $query="
+SELECT InChanger     AS online,
+       VolBytes      AS nb_bytes,
+       VolumeName    AS volumename,
+       VolStatus     AS volstatus,
+       VolMounts     AS nb_mounts,
+       Media.VolUseDuration   AS voluseduration,
+       Media.MaxVolJobs AS maxvoljobs,
+       Media.MaxVolFiles AS maxvolfiles,
+       Media.MaxVolBytes AS maxvolbytes,
+       VolErrors     AS nb_errors,
+       Pool.Name     AS poolname,
+       Location.Location AS location,
+       Media.Recycle AS recycle,
+       Media.VolRetention AS volretention,
+       Media.LastWritten  AS lastwritten,
+       Media.VolReadTime/1000000  AS volreadtime,
+       Media.VolWriteTime/1000000 AS volwritetime,
+       Media.RecycleCount AS recyclecount,
+       Media.Comment      AS comment,
+       $self->{sql}->{FROM_UNIXTIME}(
+          $self->{sql}->{UNIX_TIMESTAMP}(Media.LastWritten) 
+        + $self->{sql}->{TO_SEC}(Media.VolRetention)
+       ) AS expire
+ FROM Pool,
+      Media LEFT JOIN Location ON (Media.LocationId = Location.LocationId)
+ WHERE Pool.PoolId = Media.PoolId
+ AND VolumeName IN ($medias->{jmedias})
+";
+
+    my $all = $self->dbh_selectall_hashref($query, 'volumename') ;
+
+    foreach my $media (values %$all) {
+       my $mq = $self->dbh_quote($media->{volumename});
+
+       $query = "
+SELECT DISTINCT Job.JobId AS jobid,
+                Job.Name  AS name,
+                Job.StartTime AS starttime,
+               Job.Type  AS type,
+                Job.Level AS level,
+                Job.JobFiles AS files,
+               Job.JobBytes AS bytes,
+                Job.jobstatus AS status
+ FROM Media,JobMedia,Job
+ WHERE Media.VolumeName=$mq
+ AND Media.MediaId=JobMedia.MediaId              
+ AND JobMedia.JobId=Job.JobId
+";
+
+       my $jobs = $self->dbh_selectall_hashref($query, 'jobid') ;
+
+       $query = "
+SELECT LocationLog.Date    AS date,
+       Location.Location   AS location,
+       LocationLog.Comment AS comment
+ FROM Media,LocationLog INNER JOIN Location ON (LocationLog.LocationId = Location.LocationId)
+ WHERE Media.MediaId = LocationLog.MediaId
+   AND Media.VolumeName = $mq
+";
+
+       my $logtxt = '';
+       my $log = $self->dbh_selectall_arrayref($query) ;
+       if ($log) {
+           $logtxt = join("\n", map { ($_->[0] . ' ' . $_->[1] . ' ' . $_->[2])} @$log ) ;
+       }
+
+       $self->display({ jobs => [ values %$jobs ],
+                        LocationLog => $logtxt,
+                        %$media },
+                      "display_media_zoom.tpl");
+    }
+}
+
+sub location_edit
+{
+    my ($self) = @_ ;
+
+    my $loc = $self->get_form('qlocation');
+    unless ($loc->{qlocation}) {
+       return $self->error("Can't get location");
+    }
+
+    my $query = "
+SELECT Location.Location AS location, 
+       Location.Cost   AS cost,
+       Location.Enabled AS enabled
+FROM Location
+WHERE Location.Location = $loc->{qlocation}
+";
+
+    my $row = $self->dbh_selectrow_hashref($query);
+
+    $self->display({ ID => $cur_id++,
+                    %$row }, "location_edit.tpl") ;
+
+}
+
+sub location_save
+{
+    my ($self) = @_ ;
+
+    my $arg = $self->get_form(qw/qlocation qnewlocation cost/) ;
+    unless ($arg->{qlocation}) {
+       return $self->error("Can't get location");
+    }    
+    unless ($arg->{qnewlocation}) {
+       return $self->error("Can't get new location name");
+    }
+    unless ($arg->{cost}) {
+       return $self->error("Can't get new cost");
+    }
+
+    my $enabled = CGI::param('enabled') || '';
+    $enabled = $enabled?1:0;
+
+    my $query = "
+UPDATE Location SET Cost     = $arg->{cost}, 
+                    Location = $arg->{qnewlocation},
+                    Enabled   = $enabled
+WHERE Location.Location = $arg->{qlocation}
+";
+
+    $self->dbh_do($query);
+
+    $self->display_location();
+}
+
+sub location_del
+{
+    my ($self) = @_ ;
+    my $arg = $self->get_form(qw/qlocation/) ;
+
+    unless ($arg->{qlocation}) {
+       return $self->error("Can't get location");
+    }
+
+    my $query = "
+SELECT count(Media.MediaId) AS nb 
+  FROM Media INNER JOIN Location USING (LocationID)
+WHERE Location = $arg->{qlocation}
+";
+
+    my $res = $self->dbh_selectrow_hashref($query);
+
+    if ($res->{nb}) {
+       return $self->error("Sorry, the location must be empty");
+    }
+
+    $query = "
+DELETE FROM Location WHERE Location = $arg->{qlocation} LIMIT 1
+";
+
+    $self->dbh_do($query);
+
+    $self->display_location();
+}
+
+
+sub location_add
+{
+    my ($self) = @_ ;
+    my $arg = $self->get_form(qw/qlocation cost/) ;
+
+    unless ($arg->{qlocation}) {
+       $self->display({}, "location_add.tpl");
+       return 1;
+    }
+    unless ($arg->{cost}) {
+       return $self->error("Can't get new cost");
+    }
+
+    my $enabled = CGI::param('enabled') || '';
+    $enabled = $enabled?1:0;
+
+    my $query = "
+INSERT INTO Location (Location, Cost, Enabled) 
+       VALUES ($arg->{qlocation}, $arg->{cost}, $enabled)
+";
+
+    $self->dbh_do($query);
+
+    $self->display_location();
+}
+
+sub display_location
+{
+    my ($self) = @_ ;
+
+    my $query = "
+SELECT Location.Location AS location, 
+       Location.Cost     AS cost,
+       Location.Enabled  AS enabled,
+       (SELECT count(Media.MediaId) 
+         FROM Media 
+        WHERE Media.LocationId = Location.LocationId
+       ) AS volnum
+FROM Location
+";
+
+    my $location = $self->dbh_selectall_hashref($query, 'location');
+
+    $self->display({ ID => $cur_id++,
+                    Locations => [ values %$location ] },
+                  "display_location.tpl");
+}
+
+sub update_location
+{
+    my ($self) = @_ ;
+
+    my $medias = $self->get_selected_media_location();
+    unless ($medias) {
+       return ;
+    }
+
+    my $arg = $self->get_form('db_locations', 'qnewlocation');
+
+    $self->display({ email  => $self->{info}->{email_media},
+                    %$arg,
+                     medias => [ values %$medias ],
+                  },
+                  "update_location.tpl");
+}
+
+sub get_media_max_size
+{
+    my ($self, $type) = @_;
+    my $query = 
+"SELECT avg(VolBytes) AS size
+  FROM Media 
+ WHERE Media.VolStatus = 'Full' 
+   AND Media.MediaType = '$type'
+";
+    
+    my $res = $self->selectrow_hashref($query);
+
+    if ($res) {
+       return $res->{size};
+    } else {
+       return 0;
+    }
+}
+
+sub update_media
+{
+    my ($self) = @_ ;
+
+    my $media = $self->get_form('qmedia');
+
+    unless ($media->{qmedia}) {
+       return $self->error("Can't get media");
+    }
+
+    my $query = "
+SELECT Media.Slot         AS slot,
+       PoolMedia.Name     AS poolname,
+       Media.VolStatus    AS volstatus,
+       Media.InChanger    AS inchanger,
+       Location.Location  AS location,
+       Media.VolumeName   AS volumename,
+       Media.MaxVolBytes  AS maxvolbytes,
+       Media.MaxVolJobs   AS maxvoljobs,
+       Media.MaxVolFiles  AS maxvolfiles,
+       Media.VolUseDuration AS voluseduration,
+       Media.VolRetention AS volretention,
+       Media.Comment      AS comment,
+       PoolRecycle.Name   AS poolrecycle
+
+FROM Media INNER JOIN Pool AS PoolMedia ON (Media.PoolId = PoolMedia.PoolId)
+           LEFT  JOIN Pool AS PoolRecycle ON (Media.RecyclePoolId = PoolRecycle.PoolId)
+           LEFT  JOIN Location ON (Media.LocationId = Location.LocationId)
+
+WHERE Media.VolumeName = $media->{qmedia}
+";
+
+    my $row = $self->dbh_selectrow_hashref($query);
+    $row->{volretention} = human_sec($row->{volretention});
+    $row->{voluseduration} = human_sec($row->{voluseduration});
+
+    my $elt = $self->get_form(qw/db_pools db_locations/);
+
+    $self->display({
+       %$elt,
+        %$row,
+    }, "update_media.tpl");
+}
+
+sub save_location
+{
+    my ($self) = @_ ;
+
+    my $arg = $self->get_form('jmedias', 'qnewlocation') ;
+
+    unless ($arg->{jmedias}) {
+       return $self->error("Can't get selected media");
+    }
+    
+    unless ($arg->{qnewlocation}) {
+       return $self->error("Can't get new location");
+    }
+
+    my $query = "
+ UPDATE Media 
+     SET LocationId = (SELECT LocationId 
+                       FROM Location 
+                       WHERE Location = $arg->{qnewlocation}) 
+     WHERE Media.VolumeName IN ($arg->{jmedias})
+";
+
+    my $nb = $self->dbh_do($query);
+
+    print "$nb media updated, you may have to update your autochanger.";
+
+    $self->display_media();
+}
+
+sub change_location
+{
+    my ($self) = @_ ;
+
+    my $medias = $self->get_selected_media_location();
+    unless ($medias) {
+       return $self->error("Can't get media selection");
+    }
+    my $newloc = CGI::param('newlocation');
+
+    my $user = CGI::param('user') || 'unknow';
+    my $comm = CGI::param('comment') || '';
+    $comm = $self->dbh_quote("$user: $comm");
+
+    my $query;
+
+    foreach my $media (keys %$medias) {
+       $query = "
+INSERT LocationLog (Date, Comment, MediaId, LocationId, NewVolStatus)
+ VALUES(
+       NOW(), $comm, (SELECT MediaId FROM Media WHERE VolumeName = '$media'),
+       (SELECT LocationId FROM Location WHERE Location = '$medias->{$media}->{location}'),
+       (SELECT VolStatus FROM Media WHERE VolumeName = '$media')
+      )
+";
+       $self->dbh_do($query);
+       $self->debug($query);
+    }
+
+    my $q = new CGI;
+    $q->param('action', 'update_location');
+    my $url = $q->url(-full => 1, -query=>1);
+
+    $self->display({ email  => $self->{info}->{email_media},
+                    url => $url,
+                    newlocation => $newloc,
+                    # [ { volumename => 'vol1' }, { volumename => 'vol2'\81 },..]
+                    medias => [ values %$medias ],
+                  },
+                  "change_location.tpl");
+
+}
+
+sub display_client_stats
+{
+    my ($self, %arg) = @_ ;
+
+    my $client = $self->dbh_quote($arg{clientname});
+    my ($limit, $label) = $self->get_limit(%arg);
+
+    my $query = "
+SELECT 
+    count(Job.JobId)     AS nb_jobs,
+    sum(Job.JobBytes)    AS nb_bytes,
+    sum(Job.JobErrors)   AS nb_err,
+    sum(Job.JobFiles)    AS nb_files,
+    Client.Name          AS clientname
+FROM Job INNER JOIN Client USING (ClientId)
+WHERE 
+    Client.Name = $client
+    $limit 
+GROUP BY Client.Name
+";
+
+    my $row = $self->dbh_selectrow_hashref($query);
+
+    $row->{ID} = $cur_id++;
+    $row->{label} = $label;
+
+    $self->display($row, "display_client_stats.tpl");
+}
+
+# poolname can be undef
+sub display_pool
+{
+    my ($self, $poolname) = @_ ;
+    my $whereA = '';
+    my $whereW = '';
+
+    my $arg = $self->get_form('jmediatypes', 'qmediatypes');
+    if ($arg->{jmediatypes}) {
+       $whereW = "WHERE MediaType IN ($arg->{jmediatypes}) ";
+       $whereA = "AND   MediaType IN ($arg->{jmediatypes}) ";
+    }
+    
+# TODO : afficher les tailles et les dates
+
+    my $query = "
+SELECT subq.volmax        AS volmax,
+       subq.volnum        AS volnum,
+       subq.voltotal      AS voltotal,
+       Pool.Name          AS name,
+       Pool.Recycle       AS recycle,
+       Pool.VolRetention  AS volretention,
+       Pool.VolUseDuration AS voluseduration,
+       Pool.MaxVolJobs    AS maxvoljobs,
+       Pool.MaxVolFiles   AS maxvolfiles,
+       Pool.MaxVolBytes   AS maxvolbytes,
+       subq.PoolId        AS PoolId
+FROM
+  (
+    SELECT COALESCE(media_avg_size.volavg,0) * count(Media.MediaId) AS volmax,
+           count(Media.MediaId)  AS volnum,
+           sum(Media.VolBytes)   AS voltotal,
+           Media.PoolId          AS PoolId,
+           Media.MediaType       AS MediaType
+    FROM Media
+    LEFT JOIN (SELECT avg(Media.VolBytes) AS volavg,
+                      Media.MediaType     AS MediaType
+               FROM Media 
+              WHERE Media.VolStatus = 'Full' 
+              GROUP BY Media.MediaType
+               ) AS media_avg_size ON (Media.MediaType = media_avg_size.MediaType)
+    GROUP BY Media.MediaType, Media.PoolId, media_avg_size.volavg
+  ) AS subq
+LEFT JOIN Pool ON (Pool.PoolId = subq.PoolId)
+$whereW
+";
+
+    my $all = $self->dbh_selectall_hashref($query, 'name') ;
+
+    $query = "
+SELECT Pool.Name AS name,
+       sum(VolBytes) AS size
+FROM   Media JOIN Pool ON (Media.PoolId = Pool.PoolId)
+WHERE  Media.VolStatus IN ('Recycled', 'Purged')
+       $whereA
+GROUP BY Pool.Name;
+";
+    my $empty = $self->dbh_selectall_hashref($query, 'name');
+
+    foreach my $p (values %$all) {
+       if ($p->{volmax} > 0) { # mysql returns 0.0000
+           # we remove Recycled/Purged media from pool usage
+           if (defined $empty->{$p->{name}}) {
+               $p->{voltotal} -= $empty->{$p->{name}}->{size};
+           }
+           $p->{poolusage} = sprintf('%.2f', $p->{voltotal} * 100/ $p->{volmax}) ;
+       } else {
+           $p->{poolusage} = 0;
+       }
+
+       $query = "
+  SELECT VolStatus AS volstatus, count(MediaId) AS nb
+    FROM Media 
+   WHERE PoolId=$p->{poolid} 
+         $whereA
+GROUP BY VolStatus
+";
+       my $content = $self->dbh_selectall_hashref($query, 'volstatus');
+       foreach my $t (values %$content) {
+           $p->{"nb_" . $t->{volstatus}} = $t->{nb} ;
+       }
+    }
+
+    $self->debug($all);
+    $self->display({ ID => $cur_id++,
+                    MediaType => $arg->{qmediatypes}, # [ { name => type1 } , { name => type2 } ]
+                    Pools => [ values %$all ]},
+                  "display_pool.tpl");
+}
+
+sub display_running_job
+{
+    my ($self) = @_;
+
+    my $arg = $self->get_form('client', 'jobid');
+
+    if (!$arg->{client} and $arg->{jobid}) {
+
+       my $query = "
+SELECT Client.Name AS name
+FROM Job INNER JOIN Client USING (ClientId)
+WHERE Job.JobId = $arg->{jobid}
+";
+
+       my $row = $self->dbh_selectrow_hashref($query);
+
+       if ($row) {
+           $arg->{client} = $row->{name};
+           CGI::param('client', $arg->{client});
+       }
+    }
+
+    if ($arg->{client}) {
+       my $cli = new Bweb::Client(name => $arg->{client});
+       $cli->display_running_job($self->{info}, $arg->{jobid});
+       if ($arg->{jobid}) {
+           $self->get_job_log();
+       }
+    } else {
+       $self->error("Can't get client or jobid");
+    }
+}
+
+sub display_running_jobs
+{
+    my ($self, $display_action) = @_;
+    
+    my $query = "
+SELECT Job.JobId AS jobid, 
+       Job.Name  AS jobname,
+       Job.Level     AS level,
+       Job.StartTime AS starttime,
+       Job.JobFiles  AS jobfiles,
+       Job.JobBytes  AS jobbytes,
+       Job.JobStatus AS jobstatus,
+$self->{sql}->{SEC_TO_TIME}(  $self->{sql}->{UNIX_TIMESTAMP}(NOW())  
+                            - $self->{sql}->{UNIX_TIMESTAMP}(StartTime)) 
+         AS duration,
+       Client.Name AS clientname
+FROM Job INNER JOIN Client USING (ClientId) 
+WHERE JobStatus IN ('C','R','B','e','D','F','S','m','M','s','j','c','d','t','p')
+";     
+    my $all = $self->dbh_selectall_hashref($query, 'jobid') ;
+    
+    $self->display({ ID => $cur_id++,
+                    display_action => $display_action,
+                    Jobs => [ values %$all ]},
+                  "running_job.tpl") ;
+}
+
+# return the autochanger list to update
+sub eject_media
+{
+    my ($self) = @_;
+    my %ret; 
+    my $arg = $self->get_form('jmedias');
+
+    unless ($arg->{jmedias}) {
+       return $self->error("Can't get media selection");
+    }
+
+    my $query = "
+SELECT Media.VolumeName  AS volumename,
+       Storage.Name      AS storage,
+       Location.Location AS location,
+       Media.Slot        AS slot
+FROM Media INNER JOIN Storage  ON (Media.StorageId  = Storage.StorageId)
+           LEFT  JOIN Location ON (Media.LocationId = Location.LocationId)
+WHERE Media.VolumeName IN ($arg->{jmedias})
+  AND Media.InChanger = 1
+";
+
+    my $all = $self->dbh_selectall_hashref($query, 'volumename');
+
+    foreach my $vol (values %$all) {
+       my $a = $self->ach_get($vol->{location});
+       next unless ($a) ;
+       $ret{$vol->{location}} = 1;
+
+       unless ($a->{have_status}) {
+           $a->status();
+           $a->{have_status} = 1;
+       }
+
+       print "eject $vol->{volumename} from $vol->{storage} : ";
+       if ($a->send_to_io($vol->{slot})) {
+           print "<img src='/bweb/T.png' alt='ok'><br/>";
+       } else {
+           print "<img src='/bweb/E.png' alt='err'><br/>";
+       }
+    }
+    return keys %ret;
+}
+
+sub move_email
+{
+    my ($self) = @_;
+
+    my ($to, $subject, $content) = (CGI::param('email'),
+                                   CGI::param('subject'),
+                                   CGI::param('content'));
+    $to =~ s/[^\w\d\.\@<>,]//;
+    $subject =~ s/[^\w\d\.\[\]]/ /;    
+
+    open(MAIL, "|mail -s '$subject' '$to'") ;
+    print MAIL $content;
+    close(MAIL);
+
+    print "Mail sent";
+}
+
+sub restore
+{
+    my ($self) = @_;
+    
+    my $arg = $self->get_form('jobid', 'client');
+
+    print CGI::header('text/brestore');
+    print "jobid=$arg->{jobid}\n" if ($arg->{jobid});
+    print "client=$arg->{client}\n" if ($arg->{client});
+    print "\n\nYou have to assign this mime type with /usr/bin/brestore.pl\n";
+    print "\n";
+}
+
+# TODO : move this to Bweb::Autochanger ?
+# TODO : make this internal to not eject tape ?
+use Bconsole;
+
+
+sub ach_get
+{
+    my ($self, $name) = @_;
+    
+    unless ($name) {
+       return $self->error("Can't get your autochanger name ach");
+    }
+
+    unless ($self->{info}->{ach_list}) {
+       return $self->error("Could not find any autochanger");
+    }
+    
+    my $a = $self->{info}->{ach_list}->{$name};
+
+    unless ($a) {
+       $self->error("Can't get your autochanger $name from your ach_list");
+       return undef;
+    }
+
+    $a->{bweb}  = $self;
+    $a->{debug} = $self->{debug};
+
+    return $a;
+}
+
+sub ach_register
+{
+    my ($self, $ach) = @_;
+
+    $self->{info}->{ach_list}->{$ach->{name}} = $ach;
+
+    $self->{info}->save();
+    
+    return 1;
+}
+
+sub ach_edit
+{
+    my ($self) = @_;
+    my $arg = $self->get_form('ach');
+    if (!$arg->{ach} 
+       or !$self->{info}->{ach_list} 
+       or !$self->{info}->{ach_list}->{$arg->{ach}}) 
+    {
+       return $self->error("Can't get autochanger name");
+    }
+
+    my $ach = $self->{info}->{ach_list}->{$arg->{ach}};
+
+    my $i=0;
+    $ach->{drives} = 
+       [ map { { name => $_, index => $i++ } } @{$ach->{drive_name}} ] ;
+
+    my $b = $self->get_bconsole();
+
+    my @storages = $b->list_storage() ;
+
+    $ach->{devices} = [ map { { name => $_ } } @storages ];
+    
+    $self->display($ach, "ach_add.tpl");
+    delete $ach->{drives};
+    delete $ach->{devices};
+    return 1;
+}
+
+sub ach_del
+{
+    my ($self) = @_;
+    my $arg = $self->get_form('ach');
+
+    if (!$arg->{ach} 
+       or !$self->{info}->{ach_list} 
+       or !$self->{info}->{ach_list}->{$arg->{ach}}) 
+    {
+       return $self->error("Can't get autochanger name");
+    }
+   
+    delete $self->{info}->{ach_list}->{$arg->{ach}} ;
+   
+    $self->{info}->save();
+    $self->{info}->view();
+}
+
+sub ach_add
+{
+    my ($self) = @_;
+    my $arg = $self->get_form('ach', 'mtxcmd', 'device', 'precmd');
+
+    my $b = $self->get_bconsole();
+    my @storages = $b->list_storage() ;
+
+    unless ($arg->{ach}) {
+       $arg->{devices} = [ map { { name => $_ } } @storages ];
+       return $self->display($arg, "ach_add.tpl");
+    }
+
+    my @drives ;
+    foreach my $drive (CGI::param('drives'))
+    {
+       unless (grep(/^$drive$/,@storages)) {
+           return $self->error("Can't find $drive in storage list");
+       }
+
+       my $index = CGI::param("index_$drive");
+       unless (defined $index and $index =~ /^(\d+)$/) {
+           return $self->error("Can't get $drive index");
+       }
+
+       $drives[$index] = $drive;
+    }
+
+    unless (@drives) {
+       return $self->error("Can't get drives from Autochanger");
+    }
+
+    my $a = new Bweb::Autochanger(name   => $arg->{ach},
+                                 precmd => $arg->{precmd},
+                                 drive_name => \@drives,
+                                 device => $arg->{device},
+                                 mtxcmd => $arg->{mtxcmd});
+
+    $self->ach_register($a) ;
+    
+    $self->{info}->view();
+}
+
+sub delete
+{
+    my ($self) = @_;
+    my $arg = $self->get_form('jobid');
+
+    if ($arg->{jobid}) {
+       my $b = $self->get_bconsole();
+       my $ret = $b->send_cmd("delete jobid=\"$arg->{jobid}\"");
+
+       $self->display({
+           content => $ret,
+           title => "Delete a job ",
+           name => "delete jobid=$arg->{jobid}",
+       }, "command.tpl");      
+    }
+}
+
+sub do_update_media
+{
+    my ($self) = @_ ;
+
+    my $arg = $self->get_form(qw/media volstatus inchanger pool
+                                slot volretention voluseduration 
+                                maxvoljobs maxvolfiles maxvolbytes
+                                qcomment poolrecycle
+                             /);
+
+    unless ($arg->{media}) {
+       return $self->error("Can't find media selection");
+    }
+
+    my $update = "update volume=$arg->{media} ";
+
+    if ($arg->{volstatus}) {
+       $update .= " volstatus=$arg->{volstatus} ";
+    }
+    
+    if ($arg->{inchanger}) {
+       $update .= " inchanger=yes " ;
+       if ($arg->{slot}) {
+           $update .= " slot=$arg->{slot} ";
+       }
+    } else {
+       $update .= " slot=0 inchanger=no ";
+    }
+
+    if ($arg->{pool}) {
+       $update .= " pool=$arg->{pool} " ;
+    }
+
+    if (defined $arg->{volretention}) {
+       $update .= " volretention=\"$arg->{volretention}\" " ;
+    }
+
+    if (defined $arg->{voluseduration}) {
+       $update .= " voluse=\"$arg->{voluseduration}\" " ;
+    }
+
+    if (defined $arg->{maxvoljobs}) {
+       $update .= " maxvoljobs=$arg->{maxvoljobs} " ;
+    }
+    
+    if (defined $arg->{maxvolfiles}) {
+       $update .= " maxvolfiles=$arg->{maxvolfiles} " ;
+    }    
+
+    if (defined $arg->{maxvolbytes}) {
+       $update .= " maxvolbytes=$arg->{maxvolbytes} " ;
+    }    
+
+    my $b = $self->get_bconsole();
+
+    $self->display({
+       content => $b->send_cmd($update),
+       title => "Update a volume ",
+       name => $update,
+    }, "command.tpl"); 
+
+
+    my @q;
+    my $media = $self->dbh_quote($arg->{media});
+
+    my $loc = CGI::param('location') || '';
+    if ($loc) {
+       $loc = $self->dbh_quote($loc); # is checked by db
+       push @q, "LocationId=(SELECT LocationId FROM Location WHERE Location=$loc)";
+    }
+    if ($arg->{poolrecycle}) {
+       push @q, "RecyclePoolId=(SELECT PoolId FROM Pool WHERE Name='$arg->{poolrecycle}')";
+    }
+    if (!$arg->{qcomment}) {
+       $arg->{qcomment} = "''";
+    }
+    push @q, "Comment=$arg->{qcomment}";
+    
+
+    my $query = "
+UPDATE Media 
+   SET " . join (',', @q) . "
+ WHERE Media.VolumeName = $media
+";
+    $self->dbh_do($query);
+
+    $self->update_media();
+}
+
+sub update_slots
+{
+    my ($self) = @_;
+
+    my $ach = CGI::param('ach') ;
+    $ach = $self->ach_get($ach);
+    unless ($ach) {
+       return $self->error("Bad autochanger name");
+    }
+
+    print "<pre>";
+    my $b = new Bconsole(pref => $self->{info},timeout => 60,log_stdout => 1);
+    $b->update_slots($ach->{name});
+    print "</pre>\n" 
+}
+
+sub get_job_log
+{
+    my ($self) = @_;
+
+    my $arg = $self->get_form('jobid');
+    unless ($arg->{jobid}) {
+       return $self->error("Can't get jobid");
+    }
+
+    my $t = CGI::param('time') || '';
+
+    my $query = "
+SELECT Job.Name as name, Client.Name as clientname
+ FROM  Job INNER JOIN Client ON (Job.ClientId = Client.ClientId)
+ WHERE JobId = $arg->{jobid}
+";
+
+    my $row = $self->dbh_selectrow_hashref($query);
+
+    unless ($row) {
+       return $self->error("Can't find $arg->{jobid} in catalog");
+    }
+
+    $query = "
+SELECT Time AS time, LogText AS log 
+  FROM  Log 
+ WHERE Log.JobId = $arg->{jobid} 
+    OR (Log.JobId = 0 AND Time >= (SELECT StartTime FROM Job WHERE JobId=$arg->{jobid}) 
+                      AND Time <= (SELECT COALESCE(EndTime,NOW()) FROM Job WHERE JobId=$arg->{jobid})
+       )
+ ORDER BY LogId;
+";
+
+    my $log = $self->dbh_selectall_arrayref($query);
+    unless ($log) {
+       return $self->error("Can't get log for jobid $arg->{jobid}");
+    }
+
+    my $logtxt;
+    if ($t) {
+       # log contains \n
+       $logtxt = join("", map { ($_->[0] . ' ' . $_->[1]) } @$log ) ; 
+    } else {
+       $logtxt = join("", map { $_->[1] } @$log ) ; 
+    }
+    
+    $self->display({ lines=> $logtxt,
+                    jobid => $arg->{jobid},
+                    name  => $row->{name},
+                    client => $row->{clientname},
+                }, 'display_log.tpl');
+}
+
+
+sub label_barcodes
+{
+    my ($self) = @_ ;
+
+    my $arg = $self->get_form('ach', 'slots', 'drive');
+
+    unless ($arg->{ach}) {
+       return $self->error("Can't find autochanger name");
+    }
+
+    my $a = $self->ach_get($arg->{ach});
+    unless ($a) {
+       return $self->error("Can't find autochanger name in configuration");
+    } 
+
+    my $storage = $a->get_drive_name($arg->{drive});
+    unless ($storage) {
+       return $self->error("Can't get your drive name");
+    }
+
+    my $slots = '';
+    my $t = 300 ;
+    if ($arg->{slots}) {
+       $slots = join(",", @{ $arg->{slots} });
+       $t += 60*scalar( @{ $arg->{slots} }) ;
+    }
+
+    my $b = new Bconsole(pref => $self->{info}, timeout => $t,log_stdout => 1);
+    print "<h1>This command can take long time, be patient...</h1>";
+    print "<pre>" ;
+    $b->label_barcodes(storage => $storage,
+                      drive => $arg->{drive},
+                      pool  => 'Scratch',
+                      slots => $slots) ;
+    $b->close();
+    print "</pre>";
+
+    $self->dbh_do("
+  UPDATE Media 
+       SET LocationId =   (SELECT LocationId 
+                             FROM Location 
+                            WHERE Location = '$arg->{ach}'),
+
+           RecyclePoolId = PoolId
+
+     WHERE Media.PoolId = (SELECT PoolId 
+                             FROM Pool
+                            WHERE Name = 'Scratch')
+       AND (LocationId = 0 OR LocationId IS NULL)
+");
+
+}
+
+sub purge
+{
+    my ($self) = @_;
+
+    my @volume = CGI::param('media');
+
+    unless (@volume) {
+       return $self->error("Can't get media selection");
+    }
+
+    my $b = new Bconsole(pref => $self->{info}, timeout => 60);
+
+    $self->display({
+       content => $b->purge_volume(@volume),
+       title => "Purge media",
+       name => "purge volume=" . join(' volume=', @volume),
+    }, "command.tpl"); 
+    $b->close();
+}
+
+sub prune
+{
+    my ($self) = @_;
+
+    my @volume = CGI::param('media');
+    unless (@volume) {
+       return $self->error("Can't get media selection");
+    }
+
+    my $b = new Bconsole(pref => $self->{info}, timeout => 60);
+
+    $self->display({
+       content => $b->prune_volume(@volume),
+       title => "Prune media",
+       name => "prune volume=" . join(' volume=', @volume),
+    }, "command.tpl"); 
+
+    $b->close();
+}
+
+sub cancel_job
+{
+    my ($self) = @_;
+
+    my $arg = $self->get_form('jobid');
+    unless ($arg->{jobid}) {
+       return $self->error("Can't get jobid");
+    }
+
+    my $b = $self->get_bconsole();
+    $self->display({
+       content => $b->cancel($arg->{jobid}),
+       title => "Cancel job",
+       name => "cancel jobid=$arg->{jobid}",
+    }, "command.tpl"); 
+}
+
+sub fileset_view
+{
+    # Warning, we display current fileset
+    my ($self) = @_;
+
+    my $arg = $self->get_form('fileset');
+
+    if ($arg->{fileset}) {
+       my $b = $self->get_bconsole();
+       my $ret = $b->get_fileset($arg->{fileset});
+       $self->display({ fileset => $arg->{fileset},
+                        %$ret,
+                    }, "fileset_view.tpl");
+    } else {
+       $self->error("Can't get fileset name");
+    }
+}
+
+sub director_show_sched
+{
+    my ($self) = @_ ;
+
+    my $arg = $self->get_form('days');
+
+    my $b = $self->get_bconsole();
+    my $ret = $b->director_get_sched( $arg->{days} );
+
+    $self->display({
+       id => $cur_id++,
+       list => $ret,
+    }, "scheduled_job.tpl");
+}
+
+sub enable_disable_job
+{
+    my ($self, $what) = @_ ;
+
+    my $name = CGI::param('job') || '';
+    unless ($name =~ /^[\w\d\.\-\s]+$/) {
+       return $self->error("Can't find job name");
+    }
+
+    my $b = $self->get_bconsole();
+
+    my $cmd;
+    if ($what) {
+       $cmd = "enable";
+    } else {
+       $cmd = "disable";
+    }
+
+    $self->display({
+       content => $b->send_cmd("$cmd job=\"$name\""),
+       title => "$cmd $name",
+       name => "$cmd job=\"$name\"",
+    }, "command.tpl"); 
+}
+
+sub get_bconsole
+{
+    my ($self) = @_;
+    return new Bconsole(pref => $self->{info});
+}
+
+sub run_job_select
+{
+    my ($self) = @_;
+    my $b = $self->get_bconsole();
+
+    my $joblist = [ map { { name => $_ } } $b->list_job() ];
+
+    $self->display({ Jobs => $joblist }, "run_job.tpl");
+}
+
+sub run_parse_job
+{
+    my ($self, $ouput) = @_;
+
+    my %arg;
+    foreach my $l (split(/\r\n/, $ouput)) {
+       if ($l =~ /(\w+): name=([\w\d\.\s-]+?)(\s+\w+=.+)?$/) {
+           $arg{$1} = $2;
+           $l = $3 
+               if ($3) ;
+       } 
+
+       if (my @l = $l =~ /(\w+)=([\w\d*]+)/g) {
+           %arg = (%arg, @l);
+       }
+    }
+
+    my %lowcase ;
+    foreach my $k (keys %arg) {
+       $lowcase{lc($k)} = $arg{$k} ;
+    }
+
+    return \%lowcase;
+}
+
+sub run_job_mod
+{
+    my ($self) = @_;
+    my $b = $self->get_bconsole();
+    
+    my $job = CGI::param('job') || '';
+
+    my $info = $b->send_cmd("show job=\"$job\"");
+    my $attr = $self->run_parse_job($info);
+    
+    my $jobs   = [ map {{ name => $_ }} $b->list_job() ];
+
+    my $pools  = [ map { { name => $_ } } $b->list_pool() ];
+    my $clients = [ map { { name => $_ } }$b->list_client()];
+    my $filesets= [ map { { name => $_ } }$b->list_fileset() ];
+    my $storages= [ map { { name => $_ } }$b->list_storage()];
+
+    $self->display({
+       jobs     => $jobs,
+       pools    => $pools,
+       clients  => $clients,
+       filesets => $filesets,
+       storages => $storages,
+       %$attr,
+    }, "run_job_mod.tpl");
+}
+
+sub run_job
+{
+    my ($self) = @_;
+    my $b = $self->get_bconsole();
+    
+    my $jobs   = [ map {{ name => $_ }} $b->list_job() ];
+
+    $self->display({
+       jobs     => $jobs,
+    }, "run_job.tpl");
+}
+
+sub run_job_now
+{
+    my ($self) = @_;
+    my $b = $self->get_bconsole();
+    
+    # TODO: check input (don't use pool, level)
+
+    my $arg = $self->get_form('pool', 'level', 'client', 'priority', 'when');
+    my $job = CGI::param('job') || '';
+    my $storage = CGI::param('storage') || '';
+
+    my $jobid = $b->run(job => $job,
+                       client => $arg->{client},
+                       priority => $arg->{priority},
+                       level => $arg->{level},
+                       storage => $storage,
+                       pool => $arg->{pool},
+                       when => $arg->{when},
+                       );
+
+    print $jobid, $b->{error};    
+
+    print "<br>You can follow job execution <a href='?action=dsp_cur_job;client=$arg->{client};jobid=$jobid'> here </a>";
+}
+
+1;
diff --git a/gui/bweb/lib/CCircle.pm b/gui/bweb/lib/CCircle.pm
new file mode 100644 (file)
index 0000000..0b27c64
--- /dev/null
@@ -0,0 +1,543 @@
+package CCircle ;
+
+=head1 LICENSE
+
+   Bweb - A Bacula web interface
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+
+   The main author of Bweb is Eric Bollengier.
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation plus additions
+   that are listed in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
+   Switzerland, email:ftf@fsfeurope.org.
+
+=head1 VERSION
+
+    $Id$
+
+=cut
+
+use strict ;
+use GD ;
+
+my $pi =  3.14159265;
+
+our $gd ;
+our @color_tab ; 
+
+our $black ;
+our $white ;
+
+our $last_level = 1 ;
+our @draw_label ; 
+our $height ;
+our $width ;
+
+our $cur_color = 1 ;
+
+my $debug = 0 ;
+my $font_size = 6 ;
+
+our @image_map ;
+
+sub new
+{
+    my ($class, %arg) = @_ ;
+
+    my $self = {
+       start_degrees    => 0,
+       degrees_complete => 0,
+       parent_percent   => 100,
+       level            => 1,
+       center_x         => 600,
+       center_y         => 300,
+       diameter         => 75,
+       percent_total    => 0,
+       min_percent      => 2,
+       min_total        => 0,
+       width            => 1200,
+       height           => 600,
+       min_label        => 4,
+       min_degrees      => 2,
+       max_label_level  => 2,
+       display_other    => 0,
+       base_url         => '',
+    } ;
+
+    map { $self->{$_} = $arg{$_} } keys %arg ;
+
+    unless(defined $gd) {
+       $height = $self->{height} ;
+       $width  = $self->{width} ;
+
+       $gd    = new GD::Image($width,$height);
+       $white = $gd->colorAllocate(255,255,255);
+
+       push @color_tab, ($gd->colorAllocate(135,236,88),
+                         $gd->colorAllocate(255,95,95),
+                         $gd->colorAllocate(245,207,91),
+                         $gd->colorAllocate( 255, 236, 139),
+                         $gd->colorAllocate( 255, 174, 185),
+                         $gd->colorAllocate( 179, 255,  58),
+                         $gd->colorAllocate( 205, 133,   0),
+                         $gd->colorAllocate(205, 133,   0 ),
+                         $gd->colorAllocate(238, 238, 209),
+
+                         ) ;
+                     
+
+       $black = $gd->colorAllocate(0,0,0);
+       #$gd->>transparent($white);
+       $gd->interlaced('true');
+
+       $gd->arc($self->{center_x},$self->{center_y}, 
+                $self->{diameter},$self->{diameter},
+                $self->{start_degrees},360, $black) ;
+
+    }
+
+    $self->{rayon} = $self->{diameter} / 2 ;
+
+    bless $self ;
+
+    # pour afficher les labels tout propre
+    if ($self->{level} > $last_level) {
+       $last_level = $self->{level} ;
+    }
+
+    return $self ;
+}
+
+sub calc_xy
+{
+    my ($self, $level, $deg) = @_ ;
+
+    my $x1 =   $self->{center_x}+$self->{rayon} * $level * cos($deg*$pi/180) ;
+    my $y1 =   $self->{center_y}+$self->{rayon} * $level * sin($deg*$pi/180) ;
+
+    return ($x1, $y1) ;
+
+}
+
+sub add_part
+{
+    my ($self, $percent, $label, $tips) = @_ ;
+
+    $tips = $tips || $label ;
+
+    if (($percent + $self->{percent_total}) > 100.05) {
+       print STDERR "Attention $label ($percent\% + $self->{percent_total}\%) > 100\%\n" ;
+       return undef; 
+    }
+
+    if ($percent <= 0) {
+       print STDERR "Attention $label <= 0\%\n" ;
+       return undef; 
+    }
+
+    # angle de depart de l'arc
+    my $start_degrees = (($self->{degrees_complete})?
+                        $self->{degrees_complete}:$self->{start_degrees}) ;
+
+    # angle de fin de l'arc
+    my $end_degrees = $start_degrees +
+       ($percent * ( ( $self->{parent_percent} * 360 )/100 ) ) /100 ;
+
+#    print STDERR "-------- $debug --------
+#percent = $percent%
+#label = $label
+#level = $self->{level}
+#start = $start_degrees
+#end   = $end_degrees
+#parent= $self->{parent_percent}
+#" ;
+    if (($end_degrees - $start_degrees) < $self->{min_degrees}) {
+       $self->{min_total} += $percent ;
+       return undef ;
+    }
+
+    if ($percent <= $self->{min_percent}) {
+       $self->{min_total} += $percent ;
+       return undef ;
+    }
+
+    # on totalise les % en cours
+    $self->{percent_total} += $percent ;
+
+    #print STDERR "percent_total = $self->{percent_total}\n" ;
+
+    # position dans le cercle
+    my $n = $self->{level} ; # on ajoute/retire 0.005 pour depasser un peu
+    my $m = $n+1 ;
+
+    # si c'est la premiere tranche de la nouvelle serie, il faut dessiner
+    # la premiere limite 
+
+    if ($self->{degrees_complete} == 0) {
+       my ($x1, $y1) = $self->calc_xy($n-0.005, $self->{start_degrees}) ;
+       my ($x2, $y2) = $self->calc_xy($m+0.005, $self->{start_degrees}) ;
+
+       $gd->line($x1, $y1, $x2, $y2, $black) ;
+    }
+
+    # seconde ligne
+    my ($x3, $y3) = $self->calc_xy($n-0.005, $end_degrees) ;
+
+    my ($x4, $y4) = $self->calc_xy($m+0.005, $end_degrees) ;
+
+    # ligne de bord exterieur
+    $gd->line($x3, $y3, $x4, $y4, $black);
+
+    # on dessine le bord
+    $gd->arc($self->{center_x},$self->{center_y}, 
+            $self->{diameter}*($self->{level}+1),
+            $self->{diameter}*($self->{level}+1),
+
+            $start_degrees-0.5,
+            $end_degrees+0.5, $black) ;
+
+    # on calcule le point qui est au milieu de la tranche
+    # angle = (angle nouvelle tranche)/2
+
+    # rayon = n*rayon - 0.5*rayon
+    # n=1 -> 0.5
+    # n=2 -> 1.5
+    # n=3 -> 2.5
+
+    my $mid_rad = ($end_degrees - $start_degrees) /2 + $start_degrees;
+
+    my $moy_x = ($self->{center_x}+
+                  ($self->{rayon}*$m - 0.5*$self->{rayon})
+                      *cos($mid_rad*$pi/180)) ;
+
+    my $moy_y = ($self->{center_y}+
+                  ($self->{rayon}*$m - 0.5*$self->{rayon})
+                      *sin($mid_rad*$pi/180)) ;
+
+    $gd->fillToBorder($moy_x, 
+                     $moy_y,
+                     $black,
+                     $cur_color) ;
+    
+    # on prend une couleur au hasard
+    $cur_color = ($cur_color % $#color_tab) + 1 ;
+
+    # si le % est assez grand, on affiche le label
+    if ($percent > $self->{min_label}) {
+       push @draw_label, [$label, 
+                          $moy_x, $moy_y, 
+                          $self->{level}] ;
+
+       $self->push_image_map($label, $tips, $start_degrees, $end_degrees) ;
+    }
+
+    # pour pourvoir ajouter des sous donnees
+    my $ret = new CCircle(start_degrees  => $start_degrees, 
+                         parent_percent => $percent*$self->{parent_percent}/100,
+                         level          => $m,
+                         center_x       => $self->{center_x},
+                         center_y       => $self->{center_y},
+                         min_percent    => $self->{min_percent},
+                         min_degrees    => $self->{min_degrees},
+                         base_url       => $self->{base_url} . $label,
+                         ) ;
+                
+    $self->{degrees_complete} = $end_degrees ;
+    
+    #print STDERR "$debug : [$self->{level}] $label ($percent)\n" ;
+    #open(FP, sprintf(">/tmp/img.%.3i.png", $debug)) ;
+    #print FP $gd->png;
+    #close(FP) ;
+    
+    $debug++ ;
+
+    return $ret ;
+}
+
+# on dessine le restant < min_percent
+sub finalize
+{
+    my ($self) = @_ ;
+
+    $self->add_part($self->{min_total}, 
+                   "other < $self->{min_percent}%",
+                   $black) ; 
+
+}
+
+sub set_title
+{
+    my ($self, $title) = @_ ;
+
+    $gd->string(GD::gdSmallFont, $self->{center_x} - $self->{rayon}*0.7, 
+               $self->{center_y}, $title, $black) ;
+}
+
+my $_image_map = '';
+
+sub get_imagemap
+{
+    my ($self, $title, $img) = @_ ;
+
+    return "
+<map name='testmap'>
+    $_image_map
+</map>
+<img src='$img' border=0 usemap='#testmap' alt=''>
+" ; 
+
+}
+
+sub push_image_map
+{
+    my ($self, $label, $tips, $start_degrees, $end_degrees) = @_ ;
+
+    if ($label =~ /^other .*</) {
+       if (!$self->{display_other}) {
+           return ;
+       }
+       $label = '';
+    }
+
+    # on prend des points tous les $delta sur l'arc interieur et exterieur
+
+    my $delta = 3 ;
+
+    if (($end_degrees - $start_degrees) < $delta) {
+       return ;
+    }
+
+    my @pts ;
+
+    for (my $i = $start_degrees ; 
+        $i <= $end_degrees ; 
+        $i = $i + $delta)
+    {
+       my ($x1, $y1) = $self->calc_xy($self->{level}, $i) ;
+       my ($x2, $y2) = $self->calc_xy($self->{level} + 1, $i) ;
+
+       push @pts, sprintf("%.2f,%.2f",$x1,$y1) ;
+       unshift @pts, sprintf("%.2f,%.2f",$x2, $y2) ;
+    }
+
+    my ($x1, $y1) = $self->calc_xy($self->{level}, $end_degrees) ;
+    my ($x2, $y2) = $self->calc_xy($self->{level} + 1, $end_degrees) ;
+
+    push @pts, sprintf("%.2f,%.2f",$x1,$y1) ;
+    unshift @pts, sprintf("%.2f,%.2f",$x2, $y2) ;
+
+    my $ret = join(",", @pts) ;
+
+    # on refait le traitement avec $i = $end_degrees
+    $_image_map .= "<area shape='polygon' coords='$ret' ". 
+                  "title='$tips' href='$self->{base_url}$label'>\n" ;
+
+}
+
+sub get_labels_imagemap
+{
+    my ($self) = @_ ;
+    my @ret ;
+
+    for my $l (@draw_label)
+    {
+       # translation 
+       my ($label, $x, $y, $level) = @{ $l } ;
+       
+       next if ($level > $self->{max_label_level}) ;
+
+       next if (!$self->{display_other} and $label =~ /^other .*</) ;
+
+       my $dy = ($y - $self->{center_y})*($last_level - $level) + $y ;
+
+       my $x2 ;
+       my $xp ;
+
+       if ($x < $self->{center_x}) {
+           $x2 =   $self->{center_x} 
+                 - $self->{rayon} * ($last_level + 3.7) ;
+           $xp = $x2 - (length($label) *6 + 2) ; # moins la taille de la police 
+       } else {
+           $x2 = $self->{center_x} + $self->{rayon} * ($last_level + 3.7) ;
+           $xp = $x2 + 10 ;
+       }
+
+       push @ret, $xp - 1 . ";" . $dy - 6 . ";" . $xp + length($label) * $font_size . ";" . $dy + 10 . "\n" ;
+
+       $gd->rectangle($xp - 1, $dy - 6,
+                      $xp + length($label) * $font_size, 
+                      $dy + 10, $black) ;
+    }
+}
+
+my $_label_hauteur ;
+my $_label_max ;
+my $_label_pos ;
+my $_label_init = 0 ;
+
+# on va stocker les positions dans un bitmap $_label_pos
+# 
+# si on match pas la position exacte, on essaye la case
+# au dessus ou en dessous
+# 
+# on a un bitmap pour les labels de gauche et un pour la droite
+# $_label_pos->[0] et $_label_pos->[1]
+sub get_label_pos
+{
+    my ($self, $x, $y) = @_ ;
+
+    unless ($_label_init) {
+       $_label_hauteur   = $self->{rayon} * 2 * $last_level ;
+       # nombre max de label = hauteur max / taille de la font
+       $_label_max =  $_label_hauteur / 12 ;
+       $_label_pos = [ [], [] ] ;
+       $_label_init = 1 ;
+    }
+
+    # on calcule la position du label dans le bitmap
+    use integer ;
+    my $num = $y * $_label_max / $_label_hauteur ;
+    no integer ;
+
+    my $n = 0 ;                        # nombre d'iteration
+    my $l ;
+
+    # on prend le bon bitmap
+    if ($x < $self->{center_x}) {
+       $l = $_label_pos->[0] ;
+    } else {
+       $l = $_label_pos->[1] ;
+    }      
+    
+    # on parcours le bitmap pour trouver la bonne position
+    while (($num - $n) > 0) {
+       if (not $l->[$num]) {
+           last ;
+       } elsif (not $l->[$num + $n]) {
+           $num = $num + $n ;
+           last ;
+       } elsif (not $l->[$num - $n]) {
+           $num = $num - $n ;
+           last ;
+       } 
+       $n++ ;
+    }
+    
+    $l->[$num] = 1 ;           # on prend la position
+    
+    if ($num <= 0) {
+       return 0 ;
+    }
+    
+    # calcul de la position
+    $y = $num * $_label_hauteur / $_label_max ;
+
+    return $y ;
+}
+
+sub draw_labels
+{
+    my ($self) = @_ ;
+
+    $gd->fillToBorder(1, 
+                     1,
+                     $black,
+                     $white) ;
+
+    for my $l (@draw_label)
+    {
+       # translation 
+       my ($label, $x, $y, $level) = @{ $l } ;
+
+       next if ($level > $self->{max_label_level}) ;
+
+       next if (!$self->{display_other} and $label =~ /^other .*</) ;
+
+       my $dx = ($x - $self->{center_x})*($last_level - $level) + $x ;
+       my $dy = ($y - $self->{center_y})*($last_level - $level) + $y ;
+
+       $dy = $self->get_label_pos($dx, $dy) ;
+
+       next unless ($dy) ; # pas d'affichage si pas de place
+       
+       $gd->line( $x, $y,
+                  $dx, $dy,
+                  $black) ;
+
+       my $x2 ;
+       my $xp ;
+
+       if ($x < $self->{center_x}) {
+           $x2 =   $self->{center_x} 
+                 - $self->{rayon} * ($last_level + 3.7) ;
+           $xp = $x2 - (length($label) * $font_size + 2) ; # moins la taille de la police 
+       } else {
+           $x2 = $self->{center_x} + $self->{rayon} * ($last_level + 3.7) ;
+           $xp = $x2 + 10 ;
+       }
+
+       $gd->line($dx, $dy,
+                 $x2, $dy,
+                 $black) ;
+
+       $gd->string(GD::gdSmallFont, $xp, $dy - 5, $label, $black) ;
+    }
+}
+
+1;
+__END__
+
+package main ;
+
+my $top = new CCircle() ;
+
+my $chld1 = $top->add_part(50, 'test') ;
+my $chld2 = $top->add_part(20, 'test') ;
+my $chld3 = $top->add_part(10, 'test') ;
+my $chld4 = $top->add_part(20, 'test') ;
+
+
+$chld1->add_part(20, 'test1') ;
+$chld1->add_part(20, 'test1') ;
+
+$chld2->add_part(20, 'test1') ;
+$chld2->add_part(20, 'test1') ;
+
+$chld3->add_part(20, 'test1') ;
+my $chld5 = $chld3->add_part(20, 'test1') ;
+
+$chld5->add_part(50, 'test3') ;
+
+$top->finalize() ;
+$chld1->finalize() ;
+$chld2->finalize() ;
+$chld3->finalize() ;
+$chld4->finalize() ;
+$chld5->finalize() ;
+
+$top->draw_labels() ;
+# make sure we are writing to a binary stream
+binmode STDOUT;
+
+# Convert the image to PNG and print it on standard output
+print $CCircle::gd->png;
diff --git a/gui/bweb/script/bweb-postgresql.sql b/gui/bweb/script/bweb-postgresql.sql
new file mode 100644 (file)
index 0000000..626333a
--- /dev/null
@@ -0,0 +1,41 @@
+CREATE PROCEDURAL LANGUAGE plpgsql;
+BEGIN;
+
+CREATE FUNCTION SEC_TO_TIME(timestamp with time zone)
+RETURNS timestamp with time zone AS $$
+    select date_trunc('second', $1);
+$$ LANGUAGE SQL;
+
+CREATE FUNCTION SEC_TO_TIME(bigint)
+RETURNS interval AS $$
+    select date_trunc('second', $1 * interval '1 second');
+$$ LANGUAGE SQL;
+
+CREATE FUNCTION UNIX_TIMESTAMP(timestamp with time zone)
+RETURNS double precision AS $$
+    select date_part('epoch', $1);
+$$ LANGUAGE SQL;
+
+CREATE FUNCTION SEC_TO_INT(interval)
+RETURNS double precision AS $$
+    select extract(epoch from $1);
+$$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION base64_decode_lstat(int4, varchar) RETURNS int8 AS $$
+DECLARE
+val int8;
+b64 varchar(64);
+size varchar(64);
+i int;
+BEGIN
+size := split_part($2, ' ', $1);
+b64 := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+val := 0;
+FOR i IN 1..length(size) LOOP
+val := val + (strpos(b64, substr(size, i, 1))-1) * (64^(length(size)-i));
+END LOOP;
+RETURN val;
+END;
+$$ language 'plpgsql';
+
+COMMIT;
diff --git a/gui/bweb/script/bweb.conf b/gui/bweb/script/bweb.conf
new file mode 100644 (file)
index 0000000..0427112
--- /dev/null
@@ -0,0 +1,28 @@
+<Directory /usr/lib/cgi-bin/bweb>
+        Options ExecCGI -MultiViews +SymLinksIfOwnerMatch
+
+# use this to be more safe (htpasswd -c /etc/bacula/bweb.htpasswd admin)
+#        AuthType Basic
+#        AuthName Bweb
+#        AuthUserFile /etc/bacula/bweb.htpasswd
+#        Require valid-user
+
+        AllowOverride None
+</Directory>
+
+Alias /bweb/fv /var/spool/bweb
+<Directory "/var/spool/bweb">
+    Options None
+    AllowOverride AuthConfig
+    Order allow,deny
+    Allow from all
+</Directory>
+
+Alias /bweb /usr/share/bweb/html
+<Directory "/usr/share/bweb/html">
+    Options None
+    AllowOverride AuthConfig
+    Order allow,deny
+    Allow from all
+</Directory>
+
diff --git a/gui/bweb/tpl/about.tpl b/gui/bweb/tpl/about.tpl
new file mode 100644 (file)
index 0000000..e45868a
--- /dev/null
@@ -0,0 +1,39 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> About </h1>
+</div>
+<div class='bodydiv'>
+<pre>
+   Bweb - A Bacula web interface
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+
+   The main author of Bweb is Eric Bollengier.
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation plus additions
+   that are listed in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
+   Switzerland, email:ftf@fsfeurope.org.
+
+   nrsTable Copyright 2005 New Roads School (GPL)
+   kaiska css Copyright Willy Morin (BWL)
+</pre>
+</div>
diff --git a/gui/bweb/tpl/ach_add.tpl b/gui/bweb/tpl/ach_add.tpl
new file mode 100644 (file)
index 0000000..8a8e131
--- /dev/null
@@ -0,0 +1,72 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'><TMPL_UNLESS name>New</TMPL_UNLESS> Autochanger </h1>
+</div>
+<div class='bodydiv'>
+   You have to create a Location which will have the same name.<br/><br/>
+
+   <form name='form1' action="?" method='get'>
+    <table>
+     <tr><td>Name :</td>     
+         <td>
+          <select name='ach' class='formulaire' id='ach'>
+<TMPL_LOOP devices><option value='<TMPL_VAR name>'><TMPL_VAR name></option></TMPL_LOOP>
+          </select>
+         </td>
+     </tr>
+     <tr><td>Pre-command :</td> 
+         <td> <input class="formulaire" type='text' id='precmd' value='sudo'
+           title='can be "sudo" or "ssh storage@storagehost"...' name='precmd'>
+         </td>
+     </tr>
+     <tr><td>mtx command :</td> 
+         <td> <input class="formulaire" type='text' name='mtxcmd' size='32'
+               value='/usr/sbin/mtx' id='mtxcmd'>
+         </td>
+     </tr>
+     <tr><td>Device :</td> 
+         <td> <input class="formulaire" type='text' name='device' 
+               value='/dev/changer' id='device'>
+         </td>
+     </tr>
+    <tr><td><b>Drives</b></td><td/></tr>
+    <TMPL_LOOP devices>
+    <tr>
+     <td><input class='formulaire' type='checkbox' id='drive_<TMPL_VAR name>'
+                name='drives' value='<TMPL_VAR name>'><TMPL_VAR name>
+     </td>
+     <td>index <input type='text' title='drive index' class='formulaire'
+               id='index_<TMPL_VAR name>' value='' 
+                name='index_<TMPL_VAR name>' size='3'>
+     </td>
+    </tr>
+    </TMPL_LOOP>
+    </table>
+    <input type="image" name='action' value='ach_add' src='/bweb/save.png'>
+   </form>
+</div>
+
+<script type="text/javascript" language="JavaScript">
+  <TMPL_IF name>
+  for (var i=0; i < document.form1.ach.length; ++i) {
+     if (document.form1.ach[i].value == '<TMPL_VAR name>') {
+        document.form1.ach[i].selected = true;
+     }
+  }
+  </TMPL_IF>
+  <TMPL_IF mtxcmd>
+     document.getElementById('mtxcmd').value='<TMPL_VAR mtxcmd>';
+  </TMPL_IF>
+  <TMPL_IF precmd>
+     document.getElementById('precmd').value='<TMPL_VAR precmd>';
+  </TMPL_IF>
+  <TMPL_IF device>
+     document.getElementById('device').value='<TMPL_VAR device>';
+  </TMPL_IF>
+  <TMPL_IF drives>
+   <TMPL_LOOP drives>
+     document.getElementById('drive_<TMPL_VAR name>').checked=true;
+     document.getElementById('index_<TMPL_VAR name>').value=<TMPL_VAR index>;
+   </TMPL_LOOP>
+  </TMPL_IF>
+</script>
diff --git a/gui/bweb/tpl/ach_content.tpl b/gui/bweb/tpl/ach_content.tpl
new file mode 100644 (file)
index 0000000..08952b6
--- /dev/null
@@ -0,0 +1,161 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> 
+Autochanger : <TMPL_VAR Name> (<TMPL_VAR nb_drive> Drives
+<TMPL_IF nb_io><TMPL_VAR nb_io> IMPORT/EXPORT</TMPL_IF>)</h1>
+ </div>
+ <div class='bodydiv'>
+   <form action='?' method='get'>
+    <input type='hidden' name='ach' value='<TMPL_VAR name>'>
+    <TMPL_IF "Update">
+    <font color='red'> You must run update slot, Autochanger status is different from bacula slots </font>
+    <br/>
+    </TMPL_IF>
+    <table border='0'>
+    <tr>
+    <td valign='top'>
+    <div class='otherboxtitle'>
+     Tools
+    </div>
+    <div class='otherbox'>
+<label>
+<input type="image" name='action' value='label_barcodes'
+        title='run label barcodes' src='/bweb/label.png'>Label
+</label>
+<TMPL_IF nb_io>
+<label>
+<input type="image" name='action' value='eject'
+        title='put selected media on i/o' src='/bweb/extern.png'>
+Eject
+</label>
+<label>
+<input type="image" name='action' value='clear_io'
+        title='Clear i/o' src='/bweb/intern.png'>
+Clear I/O
+</label>
+</TMPL_IF>
+<label>
+<input type="image" name='action' value='update_slots'
+        title='run update slots' src='/bweb/update.png'>
+Update
+</label>
+<br/><br/>
+<label>
+<input type="image" name='action' value='ach_load'
+       title='mount drive' src='/bweb/load.png'>
+Mount
+</label>
+<label>
+<input type="image" name='action' value='ach_unload'
+       title='umount drive' src='/bweb/unload.png'>
+Umount
+</label>
+
+   </div>
+    <td width='200'/>
+    <td>
+    <b> Drives: </b><br/>
+    <table id='id_drive'></table> <br/>
+    </td>
+    </tr>
+    </table>
+    <b> Content: </b><br/>
+    <table id='id_ach'></table>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Real Slot", "Slot", "Volume Name","Vol Bytes","Vol Status",
+                      "Media Type","Pool Name","Last Written", 
+                       "When expire ?", "Select");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP Slots>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.name = 'slot';
+chkbox.value = '<TMPL_VAR realslot>';
+
+data.push( new Array(
+"<TMPL_VAR realslot>",
+"<TMPL_VAR slot>",
+"<TMPL_VAR volumename>",
+human_size(<TMPL_VAR volbytes>),
+"<TMPL_VAR volstatus>",
+"<TMPL_VAR mediatype>",
+"<TMPL_VAR name>",
+"<TMPL_VAR lastwritten>",
+"<TMPL_VAR expire>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id_ach",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+// page_nav: true,
+// rows_per_page: rows_per_page,
+// disable_sorting: new Array(5,6)
+ padding: 3
+}
+);
+
+var header = new Array("Index", "Drive Name", "Volume Name", "Select");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP Drives>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.name = 'drive';
+chkbox.value = '<TMPL_VAR index>';
+
+data.push( new Array(
+"<TMPL_VAR index>",
+"<TMPL_VAR name>",
+"<TMPL_VAR load>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id_drive",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+// page_nav: true,
+// rows_per_page: rows_per_page,
+// disable_sorting: new Array(5,6),
+ padding: 3
+}
+);
+
+</script>
diff --git a/gui/bweb/tpl/begin.tpl b/gui/bweb/tpl/begin.tpl
new file mode 100644 (file)
index 0000000..316ea22
--- /dev/null
@@ -0,0 +1,66 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+<head>
+<title>Bweb - Bacula Web Interface</title>
+<link rel="SHORTCUT ICON" href="/bweb/favicon.ico">
+<script type="text/javascript" language="JavaScript" src="/bweb/natcompare.js"></script>
+<script type="text/javascript" language="JavaScript" src="/bweb/nrs_table.js"></script>
+<script type="text/javascript" language="JavaScript" src="/bweb/bweb.js"></script>
+<link type="text/css" rel="stylesheet" href="/bweb/style.css"/>
+<link type="text/css" rel="stylesheet" href="/bweb/kaiska.css"/>
+<link type="text/css" rel="stylesheet" href="/bweb/bweb.css"/>
+</head>
+<body>
+
+<script type="text/javascript" language="JavaScript">
+if (navigator.appName == 'Konqueror') {
+        alert("Sorry at this moment, bweb works only with mozilla.");
+}
+</script>
+
+<ul id="menu">
+ <li><a href="bweb.pl?">Main</a> </li>
+ <li><a href="bweb.pl?action=client">Clients</a></li>
+ <li><a href="bweb.pl?action=run_job">Jobs</a>
+   <ul> 
+     <li><a href="bweb.pl?action=run_job">Defined Jobs</a>
+     <li><a href="bweb.pl?action=job">Last Jobs</a> </li>
+     <li><a href="bweb.pl?action=running">Running Jobs</a>
+     <li><a href="bweb.pl?action=next_job">Next Jobs</a> </li>
+     <li><a href="bweb.pl?action=restore" title="Launch brestore">Restore</a> </li>
+   </ul>
+ </li>
+ <li style="padding: 0.25em 2em;">Media
+  <ul>
+     <li><a href="bweb.pl?action=pool">Pools</a> </li>
+     <li><a href="bweb.pl?action=location">Locations</a> </li>
+     <li><a href="bweb.pl?action=media">All Media</a><hr></li>
+     <li><a href="bweb.pl?action=extern_media">Eject Media</a> </li>
+     <li><a href="bweb.pl?action=intern_media">Load Media</a> </li>
+  </ul>
+ </li>
+<TMPL_IF achs>
+ <li style="padding: 0.25em 2em;">Autochanger
+  <ul>
+<TMPL_LOOP achs>
+   <li><a href="bweb.pl?action=ach_view;ach=<TMPL_VAR name>"><TMPL_VAR name></a></li>
+</TMPL_LOOP>
+  </ul>
+ </li>
+</TMPL_IF> 
+ <li><a href="bweb.pl?action=graph"> Statistics </a></li>
+ <li> <a href="bweb.pl?action=view_conf"> Configuration </a> </li>
+ <li> <a href="bweb.pl?action=about"> About </a> </li>
+ <li style="padding: 0.25em 2em;float: right;">&nbsp;Logged as <TMPL_VAR NAME=loginname> </li>
+ <li style="float: right;white-space: nowrap;">
+<input type="image" class="button" title="search media" onclick="search_media();" src="/bweb/tape.png"><input type="image" title="search client" onclick="search_client();" src="/bweb/client.png">&nbsp;<input class='formulaire' style="margin: 0 2px 0 2px; padding: 0 0 0 0;" id='searchbox' type='text' size='8' value="search..." onclick="this.value='';" title="search media or client"></li>
+</ul>
+
+<form name="search" action="bweb.pl?" method='GET'>
+ <input type="hidden" name="action" value="">
+ <input type="hidden" name="re_media" value="">
+ <input type="hidden" name="re_client" value="">
+</form>
+
+<div style="clear: left;">
+<div style="float: left;">
diff --git a/gui/bweb/tpl/change_location.tpl b/gui/bweb/tpl/change_location.tpl
new file mode 100644 (file)
index 0000000..d7f9651
--- /dev/null
@@ -0,0 +1,37 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> 
+   Move media
+  </h1>
+ </div>
+ <div class='bodydiv'>
+
+<form action="?" method='GET'>
+<table>
+<tr>
+<td><b>To: </b></td><td><input class='formulaire' name='email' value='<TMPL_VAR email>'></td>
+</tr><tr>
+<td><b>Subject: </b></td><td><input class='formulaire' name='subject' value='[BACULA] Move media to <TMPL_VAR newlocation>' size='80'></td>
+</tr><tr>
+<td></td>
+<td>
+<textarea name='content' class='formulaire' cols='80' rows='32'>
+Hi,
+
+Could you move these media to <TMPL_VAR newlocation>
+Media :
+<TMPL_LOOP Medias>
+ - <TMPL_VAR VolumeName>  (<TMPL_VAR location>)
+</TMPL_LOOP>
+
+When it's finish, could you update media location ? 
+(you can use this link : <TMPL_VAR url>).
+
+Thanks
+</textarea>
+</td></tr></table>
+<input class='formulaire' type='submit' name='action' value='move_email'>
+</form>
+<br>
+<a href="<TMPL_VAR url>"><img alt='update now' src='/bweb/update.png'>Update now</a>
+</div>
diff --git a/gui/bweb/tpl/client_job_status.tpl b/gui/bweb/tpl/client_job_status.tpl
new file mode 100644 (file)
index 0000000..c46ccc3
--- /dev/null
@@ -0,0 +1,40 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> 
+       Running job <TMPL_VAR JobName> on <TMPL_VAR Client>
+  </h1>
+ </div>
+ <div class='bodydiv'>
+
+<table>
+ <tr>
+  <td> <b> JobName: </b> <td> <td> <TMPL_VAR jobname> (<TMPL_VAR jobid>) <td> 
+ </tr>
+ <tr>
+  <td> <b> Processing file: </b> <td> <td> <TMPL_VAR "processing file"> </td>
+ </tr>
+ <tr>
+  <td> <b> Speed: </b> <td> <td> <TMPL_VAR "bytes/sec"> B/s</td>
+ </tr>
+ <tr>
+  <td> <b> Files Examined: </b> <td> <td> <TMPL_VAR "files examined"></td>
+ </tr>
+ <tr>
+  <td> <b> Bytes: </b> <td> <td> <TMPL_VAR bytes></td>
+ </tr>
+</table>
+<form name='form1' action='?' method='GET'>
+<input type="image" name='action' value='dsp_cur_job' 
+ src='/bweb/update.png' title='refresh'>&nbsp;
+<input type='hidden' name='client' value='<TMPL_VAR Client>'>
+<input type='hidden' name='jobid' value='<TMPL_VAR JobId>'>
+<input type="image" name='action' value='cancel_job'
+       onclick="return confirm('Do you want to cancel this job ?')"
+        title='Cancel job' src='/bweb/cancel.png'>&nbsp;
+</form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+  bweb_add_refresh();
+</script>
+
diff --git a/gui/bweb/tpl/client_list.tpl b/gui/bweb/tpl/client_list.tpl
new file mode 100644 (file)
index 0000000..c5da53e
--- /dev/null
@@ -0,0 +1,70 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Clients</h1>
+ </div>
+ <div class='bodydiv'>
+<form action='?' method='GET'>
+     <table id='id<TMPL_VAR NAME=ID>'></table>
+       <div class="otherboxtitle">
+          Actions &nbsp;
+        </div>
+        <div class="otherbox">
+<!--        <h1>Actions</h1> -->       
+       <label>
+       <input type="image" name='action' value='job' title='Show last job' src='/bweb/zoom.png'>Last jobs</label> &nbsp;
+       <label>
+       <input type="image" name='action' value='dsp_cur_job' title='Show current job' src='/bweb/zoom.png'>Current jobs</label> &nbsp;
+       <label>
+       <input type="image" name='action' value='client_status' title='Show client status' src='/bweb/zoom.png'>Status</label> &nbsp;
+       <label>
+       <input type="image" name='action' value='client_stats' title='Client stats' src='/bweb/chart.png'>Stats</label> &nbsp;
+       </label>
+        </div>
+
+</form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+var header = new Array("Name", "Select", "Desc", "Auto Prune", "File Retention", "Job Retention");
+
+var data = new Array();
+var chkbox ;
+
+<TMPL_LOOP NAME=Clients>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.name = 'client';
+chkbox.value = '<TMPL_VAR NAME=Name>';
+
+data.push( 
+  new Array( "<TMPL_VAR NAME=Name>", 
+             chkbox,
+            "<TMPL_VAR NAME=Uname>",
+            "<TMPL_VAR NAME=AutoPrune>",
+            human_sec(<TMPL_VAR NAME=FileRetention>),
+            human_sec(<TMPL_VAR NAME=JobRetention>)
+              )
+) ; 
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR NAME=ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+ disable_sorting: new Array(1)
+}
+);
+</script>
diff --git a/gui/bweb/tpl/command.tpl b/gui/bweb/tpl/command.tpl
new file mode 100644 (file)
index 0000000..ce9a906
--- /dev/null
@@ -0,0 +1,9 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> <TMPL_VAR title> : <TMPL_VAR name></h1>
+ </div>
+ <div class='bodydiv'>
+  <pre id='log' style='font-size: 10px'>
+<TMPL_VAR content>
+  </pre>
+ </div>
diff --git a/gui/bweb/tpl/config_edit.tpl b/gui/bweb/tpl/config_edit.tpl
new file mode 100644 (file)
index 0000000..5bb3466
--- /dev/null
@@ -0,0 +1,50 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Configuration </h1>
+</div>
+<div class='bodydiv'>
+   <form action="?" method='post'>
+    <table>
+     <tr>  <td><b>SQL Connection</b></td>  <td/></tr>
+     <tr><td>DBI :</td>     
+         <td> 
+          <input class="formulaire" type='text' value='<TMPL_VAR dbi>' size='64' name='dbi'> 
+         </td>
+     </tr>
+     <tr><td>user :</td> 
+         <td> <input class="formulaire" type='text' value='<TMPL_VAR user>' name='user'>
+         </td>
+     </tr>
+     <tr><td>password :</td> 
+         <td> <input class="formulaire" type='password' value='<TMPL_VAR password>' name='password'> 
+         </td></tr>
+
+     <tr>  <td><b>General Options</b></td>  <td/></tr>
+
+     <tr><td>email_media :</td> 
+         <td> <input class="formulaire" type='text' value='<TMPL_VAR email_media>' name='email_media'> 
+         </td></tr>
+         </td></tr>
+
+     <tr>  <td><b>Bweb Configuration</b></td>  <td/></tr>
+
+     <tr><td>graph_font :</td> 
+         <td> <input class="formulaire" type='text' value='<TMPL_VAR graph_font>' size='64' name='graph_font'> 
+         </td></tr>
+     <tr><td>template_dir :</td> 
+         <td> <input class="formulaire" type='text' value='<TMPL_VAR template_dir>' size='64' name='template_dir'> 
+         </td></tr>
+     <tr><td>fv_write_path :</td> 
+         <td> <input class="formulaire" title="This folder must be writable by apache user and must be accessible on /bweb/fv" type='text' value='<TMPL_VAR fv_write_path>' size='64' name='fv_write_path'> 
+         </td></tr>
+     <tr><td>bconsole :</td> 
+         <td> <input class="formulaire" type='text' value='<TMPL_VAR bconsole>' size='64' name='bconsole'> 
+         </td></tr>
+     <tr><td>debug :</td> 
+         <td> <input class="formulaire" type='checkbox' name='debug' <TMPL_IF debug> checked='checked' value='on' </TMPL_IF> > 
+         </td></tr>
+    </table>
+    <input type="image" name='action' value='apply_conf' src='/bweb/save.png'>
+   </form>
+</div>
diff --git a/gui/bweb/tpl/config_view.tpl b/gui/bweb/tpl/config_view.tpl
new file mode 100644 (file)
index 0000000..a505b03
--- /dev/null
@@ -0,0 +1,62 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Configuration </h1>
+</div>
+<div class='bodydiv'>
+   <table>
+    <tr>  <td><b>SQL Connection</b></td>  <td/></tr>
+    <tr><td>DBI :</td>      <td> <TMPL_VAR dbi>      </td></tr>
+    <tr><td>user :</td>     <td> <TMPL_VAR user>     </td></tr>
+    <tr><td>password :</td> <td> xxxxx </td></tr>
+    <tr>  <td><b>General Options</b></td>  <td/></tr>
+    <tr><td>email_media :</td> <td> <TMPL_VAR email_media> </td></tr>
+    <tr>  <td><b>Bweb Configuration</b></td>  <td/></tr>
+    <tr><td>config_file :</td> <td> <TMPL_VAR config_file> </td></tr>
+    <tr><td title="/path/to/your/template_dir">template_dir :</td> <td> <TMPL_VAR template_dir> </td></tr>
+    <tr><td title="/path/to/a/font.ttf">graph_font :</td> <td> <TMPL_VAR graph_font> </td></tr>
+    <tr><td title="This folder must be writable by apache user and must be accessible on /bweb/fv">fv_write_path :</td> <td> <TMPL_VAR fv_write_path> </td></tr>
+    <tr><td title="/path/to/bconsole -n -c /path/to/bconsole.conf">bconsole :</td> <td> <TMPL_VAR bconsole> </td></tr>
+    <tr><td>debug :</td> <td> <TMPL_VAR debug> </td></tr>
+    <TMPL_IF achs>
+    <tr>  <td><b>Autochanger</b></td>  <td/></tr>
+    <tr>
+     <td>
+     <form action='?' method='GET'>
+     <table border='0'>
+    <TMPL_LOOP achs>
+      <tr> 
+       <td>
+<label>
+ <input type='radio' name='ach' value='<TMPL_VAR name>'><TMPL_VAR name>
+</label>
+       </td>
+      </tr>
+    </TMPL_LOOP>
+    </table>
+   <td>
+  
+   <input type="image" name="action" value="ach_edit" title="edit" src='/bweb/edit.png'> 
+   <input type="image" name='action' value='ach_del' title='delete' src='/bweb/remove.png'>
+   <input type='image' name='action' value='ach_view' title='view' src='/bweb/zoom.png'>
+    </form>
+    </td>
+   </tr>
+   </TMPL_IF achs>
+   <tr>
+   <td><hr></td><td></td>
+   </tr>
+  </table>
+
+  <form action='?' method='GET'>
+   <label>
+   <input name='action' value='edit_conf' type="image" title='Edit' src='/bweb/edit.png'> Edit
+   </label>
+   <label>
+   <input name='action' value='ach_add' type="image" title='Add an autochanger' src='/bweb/add.png'> Add autochanger
+   </label>
+  </form>
+
+  <TMPL_IF error>
+  info :  <TMPL_VAR error> </br>
+  </TMPL_IF>
+</div>
diff --git a/gui/bweb/tpl/display_client_job.tpl b/gui/bweb/tpl/display_client_job.tpl
new file mode 100644 (file)
index 0000000..33199f2
--- /dev/null
@@ -0,0 +1,65 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Last jobs for <TMPL_VAR clientname> (<TMPL_VAR Filter>)
+  </h1>
+ </div>
+ <div class='bodydiv'>
+
+   <table id='id<TMPL_VAR ID>'></table>
+
+<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_size;status=T">
+    <img src="/bweb/chart.png" alt="backup size" title="backup size evolution"/>
+    </a>
+<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_duration;status=T">
+    <img src="/bweb/chart.png" alt="backup duration" title="backup time evolution"/>
+    </a>
+<a href="bgraph.pl?client=<TMPL_VAR clientname>;action=job_rate;status=T">
+    <img src="/bweb/chart.png" alt="backup rate" title="backup rate evolution"/>
+    </a>                               
+ </div>
+
+
+<script type="text/javascript" language="JavaScript">
+var header = new Array("JobId", "Job Name", "File Set", "Level", "Start Time", 
+                  "Job Files", "Job Bytes", "Errors");
+
+var data = new Array();
+
+<TMPL_LOOP Jobs>
+data.push( new Array(
+"<TMPL_VAR JobId>",
+"<TMPL_VAR JobName>",    
+"<TMPL_VAR FileSet>",
+"<TMPL_VAR Level>",
+"<TMPL_VAR StartTime>",
+"<TMPL_VAR JobFiles>",   
+human_size(<TMPL_VAR JobBytes>),
+"<TMPL_VAR JobErrors>"   
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: true,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+ disable_sorting: new Array(5,6)
+}
+);
+
+// get newest job first
+nrsTables['id<TMPL_VAR ID>'].fieldSort(0);
+</script>
diff --git a/gui/bweb/tpl/display_client_stats.tpl b/gui/bweb/tpl/display_client_stats.tpl
new file mode 100644 (file)
index 0000000..d93cd8e
--- /dev/null
@@ -0,0 +1,59 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Client : <TMPL_VAR NAME=clientname> (<TMPL_VAR NAME=label>)</h1>
+ </div>
+ <div class='bodydiv'>
+<form action='?'
+     <table id='id<TMPL_VAR NAME=ID>'></table>
+     <img src="bgraph.pl?client=<TMPL_VAR NAME=clientname>;graph=job_duration;age=2592000;width=420;height=200" alt='Not enough data' > &nbsp;
+     <img src="bgraph.pl?client=<TMPL_VAR NAME=clientname>;graph=job_rate;age=2592000;width=420;height=200" alt='Not enough data'> &nbsp;
+     <img src="bgraph.pl?client=<TMPL_VAR NAME=clientname>;graph=job_size;age=2592000;width=420;height=200" alt='Not enough data'> &nbsp;
+<!--   <div class="otherboxtitle">
+          Actions &nbsp;
+        </div>
+        <div class="otherbox">
+       <h1>Actions</h1> 
+       <input type="image" name='action' value='job' title='Show last job'
+        src='/bweb/zoom.png'> &nbsp;
+       <input type="image" name='action' value='dsp_cur_job' title='Show current job' src='/bweb/zoom.png'> &nbsp;
+       <input type="image" name='action' value='client_stat' title='Client stats' src='/bweb/zoom.png'> &nbsp;
+        </div>
+-->
+</form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+var header = new Array("Name", "Nb Jobs", "Nb Bytes", "Nb Files", "Nb Errors");
+
+var data = new Array();
+
+data.push( 
+  new Array( "<TMPL_VAR NAME=clientname>", 
+            "<TMPL_VAR NAME=nb_jobs>",
+            human_size(<TMPL_VAR NAME=nb_bytes>),
+            "<TMPL_VAR NAME=nb_files>",
+            "<TMPL_VAR NAME=nb_err>"
+             )
+) ; 
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR NAME=ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+// disable_sorting: new Array(1),
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/tpl/display_form_job.tpl b/gui/bweb/tpl/display_form_job.tpl
new file mode 100644 (file)
index 0000000..370a8e1
--- /dev/null
@@ -0,0 +1,126 @@
+<br/>
+<div class="otherboxtitle">
+  Filter &nbsp;
+</div>
+<div class="otherbox">
+<form name='form1' action='?' method='GET'>
+<table border='0'>
+<tr>
+  <td valign='top'>
+    <h2>Level</h2>
+    <select name='level' class='formulaire'>
+      <option id='level_Any' value='Any'>Any</option>
+      <option id='level_F' value='F'>Full</option>
+      <option id='level_D' value='D'>Differential</option>
+      <option id='level_I' value='I'>Incremental</option>
+    </select>     
+  </td>
+</tr>
+<tr>
+ <td valign='top'>
+    <h2>Status</h2>
+    <select name='status' class='formulaire'>
+      <option id='status_Any' value='Any'>Any</option>
+      <option id='status_T'   value='T'>Ok</option>
+      <option id='status_f'   value='f'>Error</option>
+      <option id='status_A'   value='A'>Canceled</option>
+    </select>     
+  </td>
+</tr>
+<tr>
+ <td valign='top'>
+    <h2>Pool</h2>
+    <select name='pool' class='formulaire'>
+      <option id='pool_all' value=''>All</option>
+<TMPL_LOOP NAME=db_pools>
+      <option id='pool_<TMPL_VAR name>'><TMPL_VAR name></option>
+</TMPL_LOOP>
+    </select>
+  </td>
+</tr>
+<tr>
+  <td valign='top'>
+    <h2>Age</h2>
+    <select name='age' class='formulaire'>
+      <option id='age_604800'   value='604800'>This week</option>
+      <option id='age_2678400'  value='2678400'>Last 30 days</option>
+      <option id='age_15552000' value='15552000'>Last 6 month</option>
+    </select>     
+  </td>
+ </tr>
+ <tr>
+  <td valign='bottom'> 
+    <h2>Number of items</h2>
+    <input type='text' name='limit' value='<TMPL_VAR NAME=limit>' 
+       class='formulaire' size='4'>
+  </td>
+</tr>
+<tr>
+  <td valign='top'> 
+    <h2>Job Type</h2>
+    <select name='jobtype' class='formulaire'>
+      <option id='jobtype_any' value='all type'>Any</option>
+      <option id='jobtype_B' value='B'>Backup</option>
+      <option id='jobtype_R' value='R'>Restore</option>
+    </select>
+  </td>
+</tr>
+<tr>
+  <td valign='top'> 
+    <h2>Clients</h2>
+    <select name='client' size='15' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_clients>
+      <option id='client_<TMPL_VAR clientname>'><TMPL_VAR clientname></option>
+</TMPL_LOOP>
+    </select>
+  </td>
+</tr>
+<!--
+<tr>
+  <td valign='top'> 
+    <h2>File Set</h2>
+    <select name='fileset' size='15' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_filesets>
+      <option id='client_<TMPL_VAR fileset>'><TMPL_VAR NAME=fileset></option>
+</TMPL_LOOP>
+    </select>
+  </td>
+</tr>
+-->
+</table>
+  <input type="image" name='action' value='job' src='/bweb/update.png'>
+
+</form>
+</div>
+<script type="text/javascript" language="JavaScript">
+
+  <TMPL_LOOP qclients>
+     document.getElementById('client_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+  <TMPL_IF status>
+     document.getElementById('status_<TMPL_VAR status>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF level>
+     document.getElementById('level_<TMPL_VAR level>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF age>
+     document.getElementById('age_<TMPL_VAR age>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF jobtype>
+     document.getElementById('jobtype_<TMPL_VAR jobtype>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_LOOP qfilesets>
+     document.getElementById('fileset_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+  <TMPL_LOOP qpools>
+     document.getElementById('pool_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+</script>
+
diff --git a/gui/bweb/tpl/display_form_media.tpl b/gui/bweb/tpl/display_form_media.tpl
new file mode 100644 (file)
index 0000000..4cea050
--- /dev/null
@@ -0,0 +1,91 @@
+<div class="otherboxtitle">
+  Filter &nbsp;
+</div>
+<div class="otherbox">
+<form name='form1' action='?' method='GET'>
+<table border='0'>
+<tr>
+  <td valign='top'>
+    <h2>Media Type</h2>
+    <select name='mediatype' class='formulaire'>
+      <option id='mediatype_all' value=''></option>
+<TMPL_LOOP NAME=db_mediatypes>
+      <option id='mediatype_<TMPL_VAR mediatype>'><TMPL_VAR mediatype></option>
+</TMPL_LOOP>
+    </select>     
+  </td>
+</tr>
+<tr>
+  <td valign='top'>
+    <h2>Location</h2>
+    <select name='location' class='formulaire'>
+      <option id='location_all>' value=''></option>
+<TMPL_LOOP NAME=db_locations>
+      <option id='location_<TMPL_VAR location>'><TMPL_VAR location></option>
+</TMPL_LOOP>
+    </select>     
+  </td>
+</tr>
+<tr>
+ <td valign='top'>
+    <h2>Status</h2>
+    <select name='volstatus' class='formulaire'>
+      <option id='volstatus_All' value=''></option>
+      <option id='volstatus_Append' value='Append'>Append</option>
+      <option id='volstatus_Full'   value='Full'>Full</option>
+      <option id='volstatus_Error'  value='Error'>Error</option>
+      <option id='volstatus_Used'   value='Used'>Used</option>
+      <option id='volstatus_Purged' value='Purged'>Purged</option>
+    </select>     
+  </td>
+</tr>
+<tr>
+ <td valign='top'>
+    <h2>Pool</h2>
+    <select name='pool' class='formulaire'>
+      <option id='pool_all>' value=''></option>
+<TMPL_LOOP NAME=db_pools>
+      <option id='pool_<TMPL_VAR name>'><TMPL_VAR name></option>
+</TMPL_LOOP>
+    </select>     
+  </td>
+</tr>
+ <tr>
+  <td valign='bottom'> 
+    <h2>Name</h2>
+    <input type='text' name='re_media' 
+      <TMPL_IF qre_media>value=<TMPL_VAR qre_media></TMPL_IF>
+       class='formulaire' size='8'>
+  </td>
+</tr>
+ <tr>
+  <td valign='bottom'> 
+    <h2>Number of items</h2>
+    <input type='text' name='limit' value='<TMPL_VAR limit>' 
+       class='formulaire' size='4'>
+  </td>
+</tr>
+
+</table>
+  <input type="image" name='action' value='media' src='/bweb/update.png'>
+
+</form>
+</div>
+<script type="text/javascript" language="JavaScript">
+  <TMPL_IF volstatus>
+     document.getElementById('volstatus_<TMPL_VAR volstatus>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_LOOP qmediatypes>
+     document.getElementById('mediatype_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+  <TMPL_LOOP qpools>
+     document.getElementById('pool_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+  <TMPL_LOOP qlocations>
+     document.getElementById('location_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+</script>
+
diff --git a/gui/bweb/tpl/display_job.tpl b/gui/bweb/tpl/display_job.tpl
new file mode 100644 (file)
index 0000000..d89b77a
--- /dev/null
@@ -0,0 +1,81 @@
+ <div class='titlediv'>
+  <h1 class='newstitle'> Last Jobs (<TMPL_VAR Filter>)</h1>
+ </div>
+ <div class='bodydiv'>
+    <table id='id<TMPL_VAR ID>'></table>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+<TMPL_IF status>
+document.getElementById('status_<TMPL_VAR status>').checked = true;
+</TMPL_IF>
+
+
+
+var header = new Array("JobId",
+                      "Client",
+                      "Job Name", 
+                      "FileSet",
+//                     "Pool",
+                       "Level",
+                       "StartTime",
+                      "Duration",
+                       "JobFiles",
+                       "JobBytes", 
+                       "Errors",
+                      "Status");
+
+var data = new Array();
+
+<TMPL_LOOP Jobs>
+a = document.createElement('A');
+a.href='?action=job_zoom;jobid=<TMPL_VAR JobId>';
+
+img = document.createElement("IMG");
+img.src=bweb_get_job_img("<TMPL_VAR JobStatus>", <TMPL_VAR joberrors>);
+img.title=jobstatus['<TMPL_VAR JobStatus>']; 
+
+a.appendChild(img);
+
+data.push( new Array(
+"<TMPL_VAR JobId>",
+"<TMPL_VAR Client>",     
+"<TMPL_VAR JobName>",    
+"<TMPL_VAR FileSet>",    
+//"<TMPL_VAR Pool>",
+"<TMPL_VAR Level>",      
+"<TMPL_VAR StartTime>",
+"<TMPL_VAR Duration>",
+"<TMPL_VAR JobFiles>",   
+human_size(<TMPL_VAR JobBytes>),
+"<TMPL_VAR joberrors>",   
+a
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: true,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+ disable_sorting: new Array(10),
+ padding: 3
+}
+);
+
+// get newest backup first
+nrsTables['id<TMPL_VAR ID>'].fieldSort(0);
+</script>
diff --git a/gui/bweb/tpl/display_job_zoom.tpl b/gui/bweb/tpl/display_job_zoom.tpl
new file mode 100644 (file)
index 0000000..f8b29fe
--- /dev/null
@@ -0,0 +1,129 @@
+ <div class='titlediv'>
+  <h1 class='newstitle'>Information about job</h1>
+ </div>
+ <div class="bodydiv">
+ <table id='id0'></table>
+ <table><td>
+ <form action='bweb.pl?'>
+  <input type='hidden' name='jobid' value='<TMPL_VAR jobid>'>
+  <label>
+  <input type="image" name='action' value='delete' title='delete this job'
+ onclick="return confirm('Do you want to delete this job from the catalog ?');"
+   src='/bweb/purge.png'> Delete
+  </label>
+ </form>
+ </td><td>
+ <form action='bweb.pl?'>
+  <TMPL_LOOP volumes>
+   <input type='hidden' name='media' value='<TMPL_VAR VolumeName>'>
+  </TMPL_LOOP>   
+  <label>
+  <input type="image" name='action' value='media' title='view media' 
+   src='/bweb/zoom.png'>View media
+  </label>
+ </form>
+ </td>
+ <td>
+ <form action='bweb.pl?'>
+  <input type='hidden' name='client' value='<TMPL_VAR Client>'>
+  <label>
+  <input type="image" name='action' value='job' title='view <TMPL_VAR Client> jobs' src='/bweb/zoom.png'>View jobs
+  </label>
+ </form>
+ </td>
+ <td>
+ <form action='bweb.pl?'>
+  <input type='hidden' name='age' value='2678400'>
+  <input type='hidden' name='client' value='<TMPL_VAR Client>'>
+  <input type='hidden' name='jobname' value='<TMPL_VAR jobname>'>
+  <label>
+  <input type="image" name='action' value='graph' title='view trends'
+   src='/bweb/chart.png'> View stats
+  </label>
+ </form>
+ </td>
+ <td>
+ <form action='bweb.pl?'>
+  <input type='hidden' name='fileset' value='<TMPL_VAR FileSet>'>
+  <label>
+  <input type="image" name='action' value='fileset_view' title='view fileset'
+   src='/bweb/zoom.png'> View FileSet
+  </label>
+ </form>
+ </td>
+<!-- Remove this to activate bfileview -->
+ <td>
+ <form action='bfileview.pl?'>
+  <input type='hidden' name='jobid' value='<TMPL_VAR jobid>'>
+  <input type='hidden' name='where' value='/'>
+  <label>
+  <input type="image" name='action' value='bfileview' title='view file usage'
+   src='/bweb/colorscm.png' onclick='if (<TMPL_VAR JobFiles> > 50000) { return confirm("It could take long time, do you want to continue ?")} else { return 1; }'> View file usage
+  </label>
+ </form>
+ </td>
+<!-- -->
+ </table>
+</div>
+
+<script type="text/javascript" language='JavaScript'>
+var header = new Array("JobId",
+                      "Client",
+                      "Job Name", 
+                      "FileSet",
+                       "Level",
+                       "StartTime", 
+                      "Duration",
+                       "JobFiles",
+                       "JobBytes",
+                       "Errors",
+                      "Pool",
+                       "Volume Name",
+                      "Status");
+
+var data = new Array();
+
+img = document.createElement("IMG");
+img.src=bweb_get_job_img("<TMPL_VAR JobStatus>", <TMPL_VAR joberrors>);
+img.title=jobstatus['<TMPL_VAR JobStatus>']; 
+
+data.push( new Array(
+"<TMPL_VAR JobId>",
+"<TMPL_VAR Client>",     
+"<TMPL_VAR JobName>",    
+"<TMPL_VAR FileSet>",    
+"<TMPL_VAR Level>",      
+"<TMPL_VAR StartTime>",
+"<TMPL_VAR duration>",
+"<TMPL_VAR JobFiles>",   
+human_size(<TMPL_VAR JobBytes>),
+"<TMPL_VAR joberrors>",
+"<TMPL_VAR poolname>",
+"<TMPL_LOOP volumes><TMPL_VAR VolumeName>\n</TMPL_LOOP>",   
+img
+ )
+);
+
+nrsTable.setup(
+{
+ table_name:     "id0",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: true,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+// disable_sorting: new Array(6)
+ padding: 3
+}
+);
+
+</script>
diff --git a/gui/bweb/tpl/display_location.tpl b/gui/bweb/tpl/display_location.tpl
new file mode 100644 (file)
index 0000000..b000758
--- /dev/null
@@ -0,0 +1,66 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'>Locations</h1>
+ </div>
+ <div class="bodydiv">
+   <form action='?' method='get'>
+    <table id='id<TMPL_VAR ID>'></table>
+    <input type="image" name='action' value='location_add' title='Add a location' src='/bweb/add.png'>&nbsp;
+    <input type="image" name='action' value='location_del' title='Remove a location' src='/bweb/remove.png'>&nbsp;
+    <input type="image" name='action' value='location_edit' title='Edit a location' src='/bweb/edit.png'>&nbsp;
+
+    <input type="image" name='action' value='media' title='Show content'
+     src='/bweb/zoom.png'>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Name","Enabled", "Cost", "Nb volumes", "Select");
+
+var data = new Array();
+var chkbox;
+
+var img;
+
+<TMPL_LOOP Locations>
+img = document.createElement('IMG');
+img.src = '/bweb/inflag<TMPL_VAR enabled>.png';
+
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'radio';
+chkbox.name  = 'location';
+chkbox.value = '<TMPL_VAR Location>';
+
+data.push( new Array(
+"<TMPL_VAR Location>",
+img,
+"<TMPL_VAR Cost>",
+"<TMPL_VAR name=volnum>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6),
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/tpl/display_log.tpl b/gui/bweb/tpl/display_log.tpl
new file mode 100644 (file)
index 0000000..251a7b0
--- /dev/null
@@ -0,0 +1,9 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Log : <TMPL_VAR name> on <TMPL_VAR client> (<TMPL_VAR jobid>)</h1>
+ </div>
+ <div class='bodydiv'>
+  <pre id='log'>
+<TMPL_VAR lines>
+  </pre>
+ </div>
diff --git a/gui/bweb/tpl/display_media.tpl b/gui/bweb/tpl/display_media.tpl
new file mode 100644 (file)
index 0000000..e4a029b
--- /dev/null
@@ -0,0 +1,91 @@
+ <div class='titlediv'>
+  <h1 class='newstitle'> 
+   Media
+  </h1>
+ </div>
+ <div class='bodydiv'>
+
+<TMPL_IF Pool>
+<h2>
+Pool : <a href="?action=pool;pool=<TMPL_VAR Pool>">
+         <TMPL_VAR Pool>
+       </a>
+</h2>
+</TMPL_IF>
+<TMPL_IF Location>
+<h2>
+Location : <TMPL_VAR location>
+</h2>
+</TMPL_IF>
+
+   <form action='?action=test' method='get'>
+    <table id='id_pool_<TMPL_VAR ID>'></table>
+      <input type="image" name='action' value='extern' title='Move out' src='/bweb/extern.png' onclick='return confirm("Do you want to eject selected media ?");'>&nbsp;
+      <input type="image" name='action' value='intern' title='Move in' src='/bweb/intern.png'>&nbsp;
+      <input type="image" name='action' value='update_media' title='Update medium' src='/bweb/edit.png'>&nbsp;
+      <input type="image" name='action' value='media_zoom' title='Information' src='/bweb/zoom.png'>&nbsp;
+<!--
+      <input type="image" name='action' value='purge' title='Purge' src='/bweb/purge.png'>&nbsp;
+-->
+      <input type="image" name='action' value='prune' title='Prune' src='/bweb/prune.png'>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Volume Name","Online","Vol Bytes", "Vol Usage", "Vol Status",
+                       "Pool", "Media Type",
+                       "Last Written", "When expire ?", "Select");
+
+var data = new Array();
+var img;
+var chkbox;
+var d;
+
+<TMPL_LOOP Medias>
+d = percent_usage(<TMPL_VAR volusage>);
+
+img = document.createElement('IMG');
+img.src = '/bweb/inflag<TMPL_VAR online>.png';
+
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.name = 'media';
+chkbox.value = '<TMPL_VAR volumename>';
+
+data.push( new Array(
+"<TMPL_VAR volumename>",
+img,
+human_size(<TMPL_VAR volbytes>),
+d,
+"<TMPL_VAR volstatus>",
+"<TMPL_VAR poolname>",
+"<TMPL_VAR mediatype>",
+"<TMPL_VAR lastwritten>",
+"<TMPL_VAR expire>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id_pool_<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+ rows_per_page: rows_per_page,
+ disable_sorting: new Array(1,3,9)
+}
+);
+</script>
diff --git a/gui/bweb/tpl/display_media_zoom.tpl b/gui/bweb/tpl/display_media_zoom.tpl
new file mode 100644 (file)
index 0000000..6dcadba
--- /dev/null
@@ -0,0 +1,163 @@
+<table>
+<td valign='top'>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Medium : <TMPL_VAR volumename> <TMPL_VAR comment></h1>
+ </div>
+ <div class='bodydiv'>
+    <b> Medium Infos</b><br/>
+    <table id='id_info_<TMPL_VAR volumename>'></table>
+    <b> Medium Stats</b><br/>
+    <table id='id_media_<TMPL_VAR volumename>'></table>
+    <b> Job List </b></br>
+    <table id='id_jobs_<TMPL_VAR volumename>'></table>
+    <b> Actions </b></br>
+   <form action='?' method='get'>
+      <input type='hidden' name='media' value='<TMPL_VAR volumename>'>
+<TMPL_IF online>&nbsp;
+      <input type="image" name='action' value='extern' onclick='return confirm("Do you want to eject this medium ?");' title='move out' src='/bweb/extern.png'>&nbsp;
+<TMPL_ELSE>
+      <input type="image" name='action' value='intern' title='move in' src='/bweb/intern.png'>&nbsp;
+</TMPL_IF>
+      <input type="image" name='action' value='update_media' title='Update' src='/bweb/edit.png'>&nbsp;
+      <input type="image" name='action' value='purge' title='Purge' src='/bweb/purge.png' onclick="return confirm('Do you want to purge this volume ?')">&nbsp;
+      <input type="image" name='action' value='prune' title='Prune' src='/bweb/prune.png'>&nbsp;
+<TMPL_IF Locationlog>
+      <a href='#' onclick='document.getElementById("locationlog").style.visibility="visible";'><img title='View location log' src='/bweb/zoom.png'></a>
+</TMPL_IF>
+   </form>
+ </div>
+</td>
+<td valign='top'style="visibility:hidden;" id='locationlog'>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Location log </h1>
+ </div>
+ <div class='bodydiv'>
+<pre>
+ <TMPL_VAR LocationLog>
+</pre>
+ </div>
+</td>
+</table>
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Pool","Online","Location","Vol Status", "Vol Bytes", "Expire",
+                      "Retention","Max use duration", "Max jobs" );
+
+var data = new Array();
+var img;
+
+img = document.createElement('IMG');
+img.src = '/bweb/inflag<TMPL_VAR online>.png';
+
+data.push( new Array(
+"<TMPL_VAR poolname>",
+img,
+"<TMPL_VAR location>",
+"<TMPL_VAR volstatus>",
+human_size(<TMPL_VAR nb_bytes>),
+"<TMPL_VAR expire>",
+human_sec(<TMPL_VAR volretention>),
+human_sec(<TMPL_VAR voluseduration>),
+"<TMPL_VAR maxvoljobs>"
+ )
+);
+
+nrsTable.setup(
+{
+ table_name:     "id_info_<TMPL_VAR volumename>",
+ table_header: header,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+ table_data: data,
+ header_color: header_color,
+ padding: 3,
+ disable_sorting: new Array(1)
+}
+);
+
+var header = new Array( "Vol Mounts", "Recycle count", "Read time", "Write time", "Errors");
+
+var data = new Array();
+data.push( new Array(
+"<TMPL_VAR nb_mounts>",
+"<TMPL_VAR recyclecount>",
+human_sec(<TMPL_VAR volreadtime>),
+human_sec(<TMPL_VAR volwritetime>),
+"<TMPL_VAR nb_errors>"
+ )
+);
+
+nrsTable.setup(
+{
+ table_name:     "id_media_<TMPL_VAR volumename>",
+ table_header: header,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+ table_data: data,
+ header_color: header_color,
+// disable_sorting: new Array()
+ padding: 3
+}
+);
+
+
+var header = new Array("JobId","Name","Start Time","Type",
+                      "Level", "Files", "Bytes", "Status");
+
+var data = new Array();
+var a;
+var img;
+
+<TMPL_LOOP jobs>
+a = document.createElement('A');
+a.href='?action=job_zoom;jobid=<TMPL_VAR JobId>';
+
+img = document.createElement("IMG");
+img.src="/bweb/<TMPL_VAR status>.png";
+img.title=jobstatus['<TMPL_VAR status>']; 
+
+a.appendChild(img);
+
+data.push( new Array(
+"<TMPL_VAR jobid>",
+"<TMPL_VAR name>",
+"<TMPL_VAR starttime>",
+"<TMPL_VAR type>",
+"<TMPL_VAR level>",
+"<TMPL_VAR files>",
+human_size(<TMPL_VAR bytes>),
+a
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id_jobs_<TMPL_VAR volumename>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6),
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/tpl/display_pool.tpl b/gui/bweb/tpl/display_pool.tpl
new file mode 100644 (file)
index 0000000..9891c83
--- /dev/null
@@ -0,0 +1,88 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'>Pools</h1>
+ </div>
+ <div class="bodydiv">
+   <form action='?' method='get'>
+    <table id='id<TMPL_VAR ID>'></table>
+    <input type="image" type='submit' name='action' value='media' title='Show content' src='/bweb/zoom.png'>
+<TMPL_LOOP MediaType>
+    <input type='hidden' name='mediatype' value=<TMPL_VAR name>>
+</TMPL_LOOP>
+   </form>
+   <br/>
+   Tips: To modify pool properties, you have to edit your Bacula configuration
+   and reload it. After, you have to run "update pool=mypool" with bconsole.
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Name","Recycle","Retention","Use Duration",
+                       "Max jobs per volume","Max files per volume", 
+                       "Max volume size","Nb volumes", "Vol Status", "Usage", "Select");
+
+var data = new Array();
+var chkbox;
+var img;
+var img2;
+
+<TMPL_LOOP Pools>
+
+img = percent_display([
+<TMPL_IF nb_recycle>{ name: "Recycle", nb: <TMPL_VAR nb_recycle> },</TMPL_IF>
+<TMPL_IF nb_purged> { name: "Purged", nb: <TMPL_VAR nb_purged> },</TMPL_IF>
+<TMPL_IF nb_append> { name: "Append", nb: <TMPL_VAR nb_append> },</TMPL_IF>
+<TMPL_IF nb_full>   { name: "Full", nb: <TMPL_VAR nb_full> },    </TMPL_IF>
+<TMPL_IF nb_disabled>   { name: "Disabled", nb: <TMPL_VAR nb_disabled> },    </TMPL_IF>
+<TMPL_IF nb_error>  { name: "Error", nb: <TMPL_VAR nb_error> },  </TMPL_IF>
+<TMPL_IF nb_archive>{ name: "Archive", nb: <TMPL_VAR nb_archive> },</TMPL_IF>
+<TMPL_IF nb_used>   { name: "Used", nb: <TMPL_VAR nb_used> },    </TMPL_IF>
+<TMPL_IF NAME='nb_read-only'> { name: "Read-Only", nb: <TMPL_VAR NAME='nb_read-only'> }, </TMPL_IF>
+{}
+]);
+
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'radio';
+chkbox.value = '<TMPL_VAR Name>';
+chkbox.name  = 'pool';
+
+img2 = percent_usage(<TMPL_VAR poolusage>);
+
+data.push( new Array(
+"<TMPL_VAR Name>",
+"<TMPL_VAR Recycle>",
+human_sec(<TMPL_VAR VolRetention>),
+human_sec(<TMPL_VAR VolUseDuration>),
+"<TMPL_VAR MaxVolJobs>",
+"<TMPL_VAR MaxVolFiles>",
+human_size(<TMPL_VAR MaxVolBytes>),
+"<TMPL_VAR VolNum>",
+img,
+img2,
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6),
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/tpl/end.tpl b/gui/bweb/tpl/end.tpl
new file mode 100644 (file)
index 0000000..072a52b
--- /dev/null
@@ -0,0 +1,5 @@
+</div>
+<div style="float: right;"></div>
+</div>
+</body>
+</html>
diff --git a/gui/bweb/tpl/error.tpl b/gui/bweb/tpl/error.tpl
new file mode 100644 (file)
index 0000000..e8d15f1
--- /dev/null
@@ -0,0 +1,4 @@
+<h1>An error has occurred :</h1>
+<pre>
+<TMPL_VAR NAME=error>
+</pre>
diff --git a/gui/bweb/tpl/fileset_view.tpl b/gui/bweb/tpl/fileset_view.tpl
new file mode 100644 (file)
index 0000000..3a53cc3
--- /dev/null
@@ -0,0 +1,20 @@
+ <div class='titlediv'>
+  <h1 class='newstitle'> 
+   FileSet <TMPL_VAR fileset>
+  </h1>
+ </div>
+ <div class='bodydiv'>
+
+ <img src="/bweb/add.png" alt="included"> What is included :
+ <pre>
+<TMPL_LOOP I><TMPL_VAR file>
+</TMPL_LOOP></pre>
+
+ <img src="/bweb/remove.png" alt="excluded"> What is excluded :
+ <pre>
+<TMPL_LOOP E><TMPL_VAR file>
+</TMPL_LOOP></pre>
+
+Tips: Warning, this is the current fileset, it could have changed ...
+
+ </div>
diff --git a/gui/bweb/tpl/fv_file_attribs.tpl b/gui/bweb/tpl/fv_file_attribs.tpl
new file mode 100644 (file)
index 0000000..858e7bd
--- /dev/null
@@ -0,0 +1,12 @@
+<div class='titlediv'>
+  <h1 class='newstitle'> Information about <TMPL_VAR filename> </h1>
+</div>
+<div class='bodydiv'>
+   <table>
+    <tr><td>size : </td> <td> <TMPL_VAR size>  </td></tr>
+    <tr><td>ctime :</td> <td> <TMPL_VAR atime> </td></tr>
+    <tr><td>mtime :</td> <td> <TMPL_VAR mtime> </td></tr>
+    <tr><td>atime :</td> <td> <TMPL_VAR atime> </td></tr>
+    <tr><td>md5 :  </td> <td> <TMPL_VAR md5>   </td></tr>
+   </table>
+</div>
diff --git a/gui/bweb/tpl/general.tpl b/gui/bweb/tpl/general.tpl
new file mode 100644 (file)
index 0000000..a862939
--- /dev/null
@@ -0,0 +1,30 @@
+
+<script type="text/javascript" language="JavaScript">
+bweb_add_refresh();
+</script>
+<div class='titlediv'>
+  <h1 class="newstitle">
+   Information
+  </h1>
+</div>
+<div class="bodydiv">
+  <table>
+   <tr><td>Total clients:</td>      <td> <TMPL_VAR nb_client> </td>
+       <td>Total bytes stored:</td> <td> <TMPL_VAR nb_bytes> </td>
+       <td>Total media:</td>        <td> <TMPL_VAR nb_media> </td>
+   </tr>
+   <tr><td>Database size:</td>      <td> <TMPL_VAR db_size> </td>
+       <td>Total Pool:</td>         <td> <TMPL_VAR nb_pool> </td>
+       <td>Total Job:</td>         <td> <TMPL_VAR nb_job> </td>
+   </tr>
+   <tr><td>Job failed (<TMPL_VAR label>):</td> 
+       
+<td <TMPL_IF nb_err> class='joberr' </TMPL_IF>>
+   <TMPL_VAR nb_err> 
+</td>
+       <td></td>         <td></td>
+       <td></td>         <td></td>
+   </tr>
+  
+  </table>
+</div>
diff --git a/gui/bweb/tpl/graph.tpl b/gui/bweb/tpl/graph.tpl
new file mode 100644 (file)
index 0000000..c80a58f
--- /dev/null
@@ -0,0 +1,171 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'>Statistics</h1>
+ </div>
+ <div class='bodydiv'>
+<table border='0'>
+<td>
+<form name='form1' action='?' method='GET'>
+        <div class="otherboxtitle">
+          Options &nbsp;
+        </div>
+        <div class="otherbox">
+<table border='0'>
+<tr>
+  <td valign='top'>
+    <h2>Level</h2>
+    <select name='level' class='formulaire'>
+      <option id='level_Any' value='Any'>Any</option>
+      <option id='level_F' value='F'>Full</option>
+      <option id='level_D' value='D'>Differential</option>
+      <option id='level_I' value='I'>Incremental</option>
+    </select>     
+  </td><td valign='top'>
+    <h2>Status</h2>
+    <select name='status' class='formulaire'>
+      <option id='status_Any' value='Any'>Any</option>
+      <option id='status_T'   value='T'>Ok</option>
+      <option id='status_f'   value='f'>Error</option>
+      <option id='status_A'   value='A'>Canceled</option>
+    </select>   
+  </td>
+</tr>
+<tr>
+  <td valign='top'>
+    <h2>Age</h2>
+    <select name='age' class='formulaire'>
+      <option id='age_604800'   value='604800'>This week</option>
+      <option id='age_2678400'  value='2678400'>Last 30 days</option>
+      <option id='age_15552000' value='15552000'>Last 6 month</option>
+    </select>     
+  </td>
+  <td  valign='top'>
+    <h2>Size</h2>
+     Width: &nbsp;<input class='formulaire' type='text' 
+                         name='width' value='<TMPL_VAR width>' size='4'><br/>
+     Height:  <input type='text' class='formulaire' 
+                name='height' value='<TMPL_VAR height>' size='4'><br/>
+  </td>
+</tr>
+<tr>
+  <td valign='top'> 
+    <h2>Clients</h2>
+    <select name='client' size='15' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_clients>
+      <option id='client_<TMPL_VAR clientname>'><TMPL_VAR clientname></option>
+</TMPL_LOOP>
+    </select>
+  </td>
+  <td valign='top'> 
+    <h2>Job Name</h2>
+    <select name='jobname' size='15' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_jobnames>
+      <option><TMPL_VAR NAME=jobname></option>
+</TMPL_LOOP>
+    </select>
+  </td>
+</tr>
+<tr>
+  <td> <h2> Type </h2> 
+ <select name='graph' class='formulaire'>
+   <option id='job_size'     value='job_size' title="Job size per job for the period">Job Size</option>
+   <option id='job_duration' value='job_duration' title="Job duration per job for the period">Job Duration</option>
+   <option id='job_rate' value='job_rate' title="Job rate per job for the period">Job Rate</option>
+   <option id='job_file' value='job_file' title="Number of backed files per job for the period">Job Files</option>
+   <option id='job_count_phour' value='job_count_phour' title="Number of jobs per hour for the period">Job per hour</option>
+   <option id='job_count_pday' value='job_count_pday' title="Number of jobs per day for the period">Job per day</option>
+   <option id='job_avg_phour' value='job_avg_pday' title="Average backup size per day for the period">Job avg B/hour</option>
+   <option id='job_avg_pday' value='job_avg_pday' title="Average backup size per hour for the period">Job avg B/day</option>
+   <option id='job_sum_phour' value='job_sum_phour' title="Job size per hour">Job total B/hour</option>
+   <option id='job_sum_pday' value='job_sum_pday' title="Job size per day">Job total B/day</option>
+   <option id='job_count_hour' value='job_count_hour' title="Number of jobs per hour for the period">Jobs Count (h)</option>
+   <option id='job_count_day' value='job_count_day' title="Number of jobs per day for the period">Jobs Count (d)</option>
+   <option id='job_avg_hour' value='job_avg_hour' title="Average backup size per hour for the period">Job avg size (h)</option>
+   <option id='job_avg_day' value='job_avg_day' title="Average backup size per day for the period">Job avg size (d)</option>
+   <option id='job_sum_hour' value='job_sum_hour' title="Job size per hour for the period">Job Bytes (h)</option>
+   <option id='job_sum_day' value='job_sum_day' title="Job size per day for the period">Job Bytes (d)</option>
+ </select>
+  </td>
+  <td valign='bottom'> 
+    <h2>Number of items</h2>
+    <input type='text' name='limit' value='<TMPL_VAR NAME=limit>' 
+        class='formulaire' size='4'>
+  </td>
+</tr>
+<tr>
+<td><h2> Graph type </h2> 
+  <select name='gtype' class='formulaire'>
+    <option id='gtype_bars' value='bars'>Bars</option>
+<!--  <option id='gtype_bars3d' value='bars3d'>Bars3d</option> -->
+    <option id='gtype_lines' value='lines'>Lines</option>
+    <option id='gtype_linespoints' value='linespoints'>Lines points</option>
+</td>
+<td>
+  <input type='submit' name='action' value='graph' class='formulaire'> 
+</td>
+</tr>
+</table>
+        </div>
+
+</form>
+</td>
+<td>
+
+ <div class="otherboxtitle">
+ Current &nbsp;
+ </div>
+ <div class="otherbox">
+ <img src='bgraph.pl?<TMPL_VAR NAME=url>' alt='Nothing to display, Try a bigger date range'>
+ </div>
+
+</td>
+</table>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+  <TMPL_LOOP qclients>
+     document.getElementById('client_' + <TMPL_VAR name>).selected = true;
+  </TMPL_LOOP>
+
+  <TMPL_IF status>
+     document.getElementById('status_<TMPL_VAR status>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF level>
+     document.getElementById('level_<TMPL_VAR level>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF age>
+     document.getElementById('age_<TMPL_VAR age>').selected=true;
+  </TMPL_IF>
+
+<TMPL_IF qfilesets>
+  for (var i=0; i < document.form1.fileset.length; ++i) {
+  <TMPL_LOOP qfilesets>
+     if (document.form1.fileset[i].value == <TMPL_VAR name>) {
+        document.form1.fileset[i].selected = true;
+     }
+  </TMPL_LOOP>
+  }
+</TMPL_IF>
+
+<TMPL_IF qjobnames>
+  for (var i=0; i < document.form1.jobname.length; ++i) {
+  <TMPL_LOOP qjobnames>
+     if (document.form1.jobname[i].value == <TMPL_VAR name>) {
+        document.form1.jobname[i].selected = true;
+     }
+  </TMPL_LOOP>
+  }
+</TMPL_IF>
+
+  <TMPL_IF graph>
+     document.getElementById('<TMPL_VAR graph>').selected=true;
+  </TMPL_IF>
+
+  <TMPL_IF gtype>
+     document.getElementById('gtype_<TMPL_VAR gtype>').selected=true;
+  </TMPL_IF>
+
+</script>
diff --git a/gui/bweb/tpl/help_extern.tpl b/gui/bweb/tpl/help_extern.tpl
new file mode 100644 (file)
index 0000000..15fd285
--- /dev/null
@@ -0,0 +1,45 @@
+<br/>
+<div class='titlediv'>
+ <h1 class='newstitle'> Help ejecting media (part 1/2)</h1>
+</div>
+<div class='bodydiv'>
+This tool will select the best candidates to eject. You will
+be asked to make your selection on the next screen. 
+  <form action="?" method='GET'>
+   <table>
+    <tr><td>Pool:</td>      
+        <td><select name='pool' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_pools>
+             <option><TMPL_VAR NAME=name></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td>Media Type:</td>      
+        <td><select name='mediatype' class='formulaire' multiple>
+<TMPL_LOOP NAME=db_mediatypes>
+             <option><TMPL_VAR NAME=mediatype></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td> Location : </td>
+        <td><select name='location' class='formulaire'>
+  <TMPL_LOOP NAME=db_locations>
+      <option id='loc_<TMPL_VAR NAME=location>' value='<TMPL_VAR NAME=location>'><TMPL_VAR NAME=location></option>
+  </TMPL_LOOP>
+    </select>
+        </td>
+    </tr>
+    <tr>
+        <td>Number of media <br/> to eject:</td> 
+        <td> <input type='text' name='limit' size='3' class='formulaire' 
+              value='10'> </td>
+    </tr>
+    <tr>
+        <td><input type="image" name='action' value='compute_extern_media' title='Next' src='/bweb/next.png'>
+        </td><td/>
+    </tr>
+   </table>
+   </form>
+</div>
diff --git a/gui/bweb/tpl/help_extern_compute.tpl b/gui/bweb/tpl/help_extern_compute.tpl
new file mode 100644 (file)
index 0000000..816353d
--- /dev/null
@@ -0,0 +1,67 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Help to eject media (part 2/2)</h1>
+ </div>
+ <div class='bodydiv'>
+  Now, you can verify the selection and eject the media.
+   <form action='?' method='get'>
+    <table id='compute'></table>
+    <table><tr>
+    <td style='align: left;'>
+    <input type="image" onclick='javascript:window.history.go(-2);' title='Back' src='/bweb/prev.png'>
+    </td><td style='align: right;'>
+    <input type="image" name='action' value='extern' src='/bweb/extern.png' title='Eject selection'>
+   </td></tr>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Volume Name","Vol Status",
+                       "Media Type","Pool Name","Last Written", 
+                       "When expire ?", "Select");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP NAME=Medias>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.value = '<TMPL_VAR NAME=volumename>';
+chkbox.name  = 'media';
+chkbox.checked = 'on';
+
+data.push( new Array(
+"<TMPL_VAR NAME=volumename>",
+"<TMPL_VAR NAME=volstatus>",
+"<TMPL_VAR NAME=mediatype>",
+"<TMPL_VAR NAME=name>",
+"<TMPL_VAR NAME=lastwritten>",
+"<TMPL_VAR NAME=expire>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "compute",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6)
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/tpl/help_intern.tpl b/gui/bweb/tpl/help_intern.tpl
new file mode 100644 (file)
index 0000000..85028ea
--- /dev/null
@@ -0,0 +1,52 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Help loading media (part 1/2)</h1>
+</div>
+<div class="bodydiv">
+This tool will select the best candidates to load. You will
+be asked to make your selection on the next screen. 
+  <form action="?" method='GET'>
+   <table>
+    <tr><td>Pool:</td>      
+        <td><select name='pool' class='formulaire' multiple>
+<TMPL_LOOP db_pools>
+             <option><TMPL_VAR name></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td>Media Type:</td>      
+        <td><select name='mediatype' class='formulaire' multiple>
+<TMPL_LOOP db_mediatypes>
+             <option><TMPL_VAR mediatype></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td>
+    Location : 
+    </td><td><select name='location' class='formulaire'>
+  <TMPL_LOOP db_locations>
+      <option value='<TMPL_VAR location>'><TMPL_VAR location></option>
+  </TMPL_LOOP>
+    </select>
+    </td>
+    </tr>
+    <tr>
+        <td>Expired :</td> 
+        <td> <input type='checkbox' name='expired' class='formulaire' 
+                checked> </td>
+    </tr>
+    <tr>
+        <td>Number of media <br/> to load:</td> 
+        <td> <input type='text' name='limit' class='formulaire' 
+                size='3' value='10'> </td>
+    </tr>
+    <tr>
+        <td><input type="image" name='action' value='compute_intern_media' 
+                title='Next' src='/bweb/next.png'>
+        </td><td/>
+    </tr>
+   </table>
+   </form>
+</div>
diff --git a/gui/bweb/tpl/help_intern_compute.tpl b/gui/bweb/tpl/help_intern_compute.tpl
new file mode 100644 (file)
index 0000000..0f10329
--- /dev/null
@@ -0,0 +1,68 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Help to load media (part 2/2)</h1>
+ </div>
+ <div class='bodydiv'>
+  Now, you can verify the selection and load the media.
+   <form action='?' method='get'>
+    <table id='compute'></table>
+    <table><tr>
+    <td style='align: left;'>
+    <input type="image" onclick='javascript:window.history.go(-2);' title='Back' src='/bweb/prev.png'>
+    </td><td style='align: right;'>
+    <input type="image" name='action' value='move_media'
+     src='/bweb/intern.png'>
+   </td></tr>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Volume Name","Vol Status",
+                       "Media Type","Pool Name","Last Written", 
+                       "When expire ?", "Select");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP NAME=Medias>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.name = 'media';
+chkbox.value= '<TMPL_VAR NAME=volumename>';
+chkbox.checked = 'on';
+
+data.push( new Array(
+"<TMPL_VAR NAME=volumename>",
+"<TMPL_VAR NAME=volstatus>",
+"<TMPL_VAR NAME=mediatype>",
+"<TMPL_VAR NAME=name>",
+"<TMPL_VAR NAME=lastwritten>",
+"<TMPL_VAR NAME=expire>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "compute",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6)
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/tpl/install.tpl b/gui/bweb/tpl/install.tpl
new file mode 100644 (file)
index 0000000..749c5d2
--- /dev/null
@@ -0,0 +1,9 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Install notes </h1>
+</div>
+<div class='bodydiv'>
+
+
+
+</div>
diff --git a/gui/bweb/tpl/location_add.tpl b/gui/bweb/tpl/location_add.tpl
new file mode 100644 (file)
index 0000000..8dd7026
--- /dev/null
@@ -0,0 +1,28 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> New location </h1>
+</div>
+<div class='bodydiv'>
+   <form action="?" method='get'>
+    <table>
+     <tr><td>Location :</td>     
+         <td> 
+          <input class="formulaire" type='text' value='' size='32' name='location'> 
+         </td>
+     </tr>
+     <tr><td>Cost :</td> 
+         <td> <input class="formulaire" type='text' value='10' name='cost' size='3'>
+         </td>
+     </tr>
+     <tr><td>Enabled :</td> 
+         <td> <input class="formulaire" type='checkbox' value='10' name='enabled'>
+         </td>
+     </tr>
+    </table>
+    <input type="image" name='action' value='location_add' title="save"
+      src='/bweb/save.png'>
+   </form>
+
+Tips: It's a good idea to have a location per autochanger. 
+
+</div>
diff --git a/gui/bweb/tpl/location_edit.tpl b/gui/bweb/tpl/location_edit.tpl
new file mode 100644 (file)
index 0000000..75ad5b6
--- /dev/null
@@ -0,0 +1,26 @@
+<br/>
+<div class='titlediv'>
+  <h1 class='newstitle'> Location : <TMPL_VAR Location></h1>
+</div>
+<div class='bodydiv'>
+   <form action="?" method='get'>
+    <input type='hidden' name='location' value='<TMPL_VAR location>'>
+    <table>
+     <tr><td>Location :</td>     
+         <td> 
+          <input class="formulaire" type='text' value='<TMPL_VAR location>' size='32' name='newlocation'> 
+         </td>
+     </tr>
+     <tr><td>Cost :</td> 
+         <td> <input class="formulaire" type='text' value='<TMPL_VAR cost>' name='cost' size='3'>
+         </td>
+     </tr>
+     <tr><td>Enabled :</td> 
+         <td> <input class="formulaire" type='checkbox' name='enabled' <TMPL_IF enabled> checked </TMPL_IF> >
+         </td>
+     </tr>
+    </table>
+    <input type="image" name='action' value='location_save'
+     src='/bweb/save.png'>
+   </form>
+</div>
diff --git a/gui/bweb/tpl/move_media.tpl b/gui/bweb/tpl/move_media.tpl
new file mode 100644 (file)
index 0000000..80520a1
--- /dev/null
@@ -0,0 +1,85 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'>Move media</h1>
+ </div>
+ <div class="bodydiv">
+   <form action='?' method='get'>
+    <table id='id<TMPL_VAR NAME=ID>'></table>
+    <table border='0'>
+    <tr><td> New location: </td><td>
+<select name='newlocation' class='formulaire'>
+    <TMPL_LOOP NAME=db_locations>
+    <option value='<TMPL_VAR NAME=location>'><TMPL_VAR NAME=location></option>
+    </TMPL_LOOP>
+</select>
+    </td></tr><tr><td> Status: </td><td>
+<select name='volstatus' class='formulaire'>
+    <option value=''>Don't update</option>
+    <option value='Append'>Append</option>
+    <option value='Archive'>Archive</option>
+    <option value='Disabled'>Disabled</option>
+    <option value='Cleaning'>Cleaning</option>
+    <option value='Error'>Error</option>
+    <option value='Full'>Full</option>
+    <option value='Purged'>Purged</option>
+    <option value='Read-Only'>Read-Only</option>
+    <option value='Recycle'>Recycle</option>
+    <option value='Used'>Used</option>
+</select>
+    </td><tr><td> User: </td><td>
+<input type='text' name='user' value='<TMPL_VAR loginname>' class='formulaire'>
+    </td></tr>
+    </td></tr><tr><td> Comment: </td><td>
+<textarea name="comment" class='formulaire'></textarea>
+    </td></tr>
+    </table>
+    <label>
+    <input type="image" type='submit' name='action' value='change_location' src='/bweb/apply.png'> Move
+    </label>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Volume Name", "Location", "Select");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP NAME=medias>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.value = '<TMPL_VAR name=volumename>';
+chkbox.name  = 'media';
+chkbox.checked = 1;
+
+data.push( new Array(
+"<TMPL_VAR NAME=volumename>",
+"<TMPL_VAR NAME=location>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR NAME=ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6),
+ rows_per_page: rows_per_page
+}
+);
+</script>
diff --git a/gui/bweb/tpl/run_job.tpl b/gui/bweb/tpl/run_job.tpl
new file mode 100644 (file)
index 0000000..85eb1f7
--- /dev/null
@@ -0,0 +1,33 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Defined jobs : </h1>
+ </div>
+ <div class='bodydiv'>
+  <form name='form1' action='?' method='GET'>  
+  <table border='0'>
+
+   <tr><td>Job Name: </td><td>
+   <select name='job'>
+    <TMPL_LOOP jobs>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+   </td></tr>
+   </table>
+   <br/>
+   <label>
+   <input type="image" name='action' value='enable_job' title='Enable'
+    src='/bweb/inflag1.png'> Enable
+   </label>
+   <label>
+   <input type="image" name='action' value='disable_job' title='Disable'
+    src='/bweb/inflag0.png'> Disable
+   </label>
+   <label>
+   <input type="image" name='action' value='run_job_mod' title='Run now'
+    src='/bweb/R.png'> Run now 
+   </label>
+  </form>
+ </div>
diff --git a/gui/bweb/tpl/run_job_mod.tpl b/gui/bweb/tpl/run_job_mod.tpl
new file mode 100644 (file)
index 0000000..5d6740c
--- /dev/null
@@ -0,0 +1,138 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Run job : <TMPL_VAR job> on <TMPL_VAR client></h1>
+ </div>
+ <div class='bodydiv'>
+  <form name='form1' action='?' method='GET'>  
+  <table border='0'>
+
+   <tr><td>Job Name: </td><td>
+   <select name='job'>
+    <TMPL_LOOP jobs>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+   </td></tr><tr><td>Pool: </td><td>
+
+   <select name='pool'>        
+     <option value=''></option>
+    <TMPL_LOOP pools>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+   </td></tr><tr><td>Client: </td><td>
+
+   <select name='client'>
+    <TMPL_LOOP clients>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+
+   </td></tr><tr><td>FileSet: </td><td>
+   <select name='fileset'>
+    <TMPL_LOOP filesets>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+
+   </td></tr><tr><td>Storage: </td><td>
+   <select name='storage'>
+    <TMPL_LOOP storages>
+     <option value='<TMPL_VAR name>'>
+       <TMPL_VAR name>
+     </option>
+    </TMPL_LOOP>
+   </select>
+
+   </td></tr><tr><td>Level: </td><td>
+   <select name='level'>
+     <option id='level_Incremental' value='Incremental'>Incremental</option>
+     <option id='level_Full' value='Full'>Full</option>
+     <option id='level_Differential' value='Differential'>Differential</option>
+   </select>
+
+   </td></tr><tr id='more1' style="visibility:hidden"><td>Start Time: </td><td>
+   <input class='formulaire' 
+         type='text' title='YYYY-MM-DD HH:MM:SS'
+          size='17' name='when' value='<TMPL_VAR when>'>
+
+   </td></tr><tr id='more2' style="visibility:hidden"><td>Priority: </td><td>
+   <input class='formulaire' type='text' 
+          size='3' name='priority' value='<TMPL_VAR priority>'>
+
+   </td></tr>
+   </table>
+   <br/>
+  <label onclick='
+           document.getElementById("more1").style.visibility="visible";
+           document.getElementById("more2").style.visibility="visible";'>
+  <img title='Display more options' src='/bweb/add.png'>More options</label>
+  <label>
+  <input type="image" name='action' value='run_job_now' title='Run job'
+   src='/bweb/R.png'>Run now
+  </label>
+  <label>
+  <input type="image" name='action' value='fileset_view' title='View FileSet'
+   src='/bweb/zoom.png'>View FileSet
+  </label>
+  </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+  <TMPL_IF job>
+     ok=1;
+     for(var i=0; ok && i < document.form1.job.length; i++) {
+       if (document.form1.job[i].value == '<TMPL_VAR job>') {
+           document.form1.job[i].selected=true;
+           ok=0;
+       }
+     }
+  </TMPL_IF>
+  <TMPL_IF client>
+     ok=1;
+     for(var i=0; ok && i < document.form1.client.length; i++) {
+       if (document.form1.client[i].value == '<TMPL_VAR client>') {
+           document.form1.client[i].selected=true;
+           ok=0;
+       }
+     }
+  </TMPL_IF>
+  <TMPL_IF pool>
+     ok=1;
+     for(var i=0; ok && i < document.form1.pool.length; i++) {
+       if (document.form1.pool[i].value == '<TMPL_VAR pool>') {
+           document.form1.pool[i].selected=true;
+           ok=0;
+       }
+     }
+  </TMPL_IF>
+  <TMPL_IF storage>
+     ok=1;
+     for(var i=0; ok && i < document.form1.storage.length; i++) {
+       if (document.form1.storage[i].value == '<TMPL_VAR storage>') {
+           document.form1.storage[i].selected=true;
+           ok=0;
+       }
+     }
+  </TMPL_IF>
+  <TMPL_IF level>
+<!--     document.getElementById('level_<TMPL_VAR level>').selected=true; -->
+  </TMPL_IF>
+  <TMPL_IF fileset>
+     ok=1;
+     for(var i=0; ok && i < document.form1.fileset.length; i++) {
+       if (document.form1.fileset[i].value == '<TMPL_VAR fileset>') {
+           document.form1.fileset[i].selected=true;
+           ok=0;
+       }
+     }
+  </TMPL_IF>
+</script>
diff --git a/gui/bweb/tpl/running_job.tpl b/gui/bweb/tpl/running_job.tpl
new file mode 100644 (file)
index 0000000..cf3655d
--- /dev/null
@@ -0,0 +1,96 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Running Jobs </h1>
+ </div>
+ <div class='bodydiv'>
+   <form action='?' method='GET'>
+   <table id='id<TMPL_VAR NAME=ID>'></table>
+   <br/>
+<label>
+<input type='image' name='action' value='dsp_cur_job' 
+ title='View job' src='/bweb/zoom.png'>
+</label>
+<label>
+<input type="image" type='submit' name='action' value='cancel_job'
+ onclick="return confirm('Do you want to cancel the selected job?')"
+ title='Cancel job' src='/bweb/cancel.png'>
+</label>
+   </form>
+
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+var header = new Array("JobId",
+                       "Client",
+                       "Job Name", 
+                       "Level",
+                       "Start Time", 
+                       "Duration", 
+//                       "Job Files",
+//                       "Job Bytes", 
+                       "Status",
+                       "Select"
+        );
+
+var data = new Array();
+var chkbox;
+var img;
+
+<TMPL_LOOP NAME=Jobs>
+a = document.createElement('A');
+a.href='?action=dsp_cur_job;jobid=<TMPL_VAR JobId>';
+
+img = document.createElement("IMG");
+img.src = '/bweb/<TMPL_VAR NAME=JobStatus>.png';
+img.title = jobstatus['<TMPL_VAR NAME=JobStatus>'];
+
+a.appendChild(img);
+
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'radio';
+chkbox.name = 'jobid';
+chkbox.value = '<TMPL_VAR NAME=jobid>';
+
+data.push( new Array(
+"<TMPL_VAR NAME=JobId>",
+"<TMPL_VAR NAME=ClientName>",     
+"<TMPL_VAR NAME=JobName>",    
+joblevel['<TMPL_VAR NAME=Level>'],      
+"<TMPL_VAR NAME=StartTime>",
+"<TMPL_VAR NAME=duration>",
+//"<TMPL_VAR NAME=JobFiles>",   
+//"<TMPL_VAR NAME=JobBytes>",
+a,
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR NAME=ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: true,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+// disable_sorting: new Array(6)
+ padding: 3
+}
+);
+
+// get newest backup first
+nrsTables['id<TMPL_VAR NAME=ID>'].fieldSort(0);
+
+bweb_add_refresh();
+
+</script>
diff --git a/gui/bweb/tpl/scheduled_job.tpl b/gui/bweb/tpl/scheduled_job.tpl
new file mode 100644 (file)
index 0000000..3657f05
--- /dev/null
@@ -0,0 +1,71 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'> Next Jobs </h1>
+ </div>
+ <div class='bodydiv'>
+    <form action='?' method='GET'>
+     <table id='id<TMPL_VAR ID>'></table>
+     <label>
+     <input type="image" name='action' value='run_job_mod'
+      src='/bweb/R.png' title='Run now'>  Run now
+     </label>
+     <label>
+      <input type="image" name='action' value='disable_job'
+       src='/bweb/inflag0.png' title='Disable'> Disable
+      </label>
+    </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Scheduled",
+                       "Level",
+                      "Type",
+                      "Priority", 
+                       "Name",
+                       "Volume",
+                      "Select");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP list>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'radio';
+chkbox.name = 'job';
+chkbox.value = '<TMPL_VAR name>';
+
+data.push( new Array(
+"<TMPL_VAR date>",    
+"<TMPL_VAR level>",
+"<TMPL_VAR type>",     
+"<TMPL_VAR priority>",    
+"<TMPL_VAR name>",      
+"<TMPL_VAR volume>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: true,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ rows_per_page: rows_per_page,
+// disable_sorting: new Array(6),
+ padding: 3
+}
+);
+</script>
diff --git a/gui/bweb/tpl/stats.tpl b/gui/bweb/tpl/stats.tpl
new file mode 100644 (file)
index 0000000..15fd57d
--- /dev/null
@@ -0,0 +1,9 @@
+<div class='titlediv'>
+  <h1 class='newstitle'> Statistics </h1>
+</div>
+<div class='bodydiv'>
+<a href='?action=job;age=172800;jobtype=B'>
+<img width='450' height='200' src='bgraph.pl?age=2678400;width=450;height=200;graph=job_sum_day;limit=500;action=graph;legend=off' alt='Nothing to display'>
+</a>
+</div>
+
diff --git a/gui/bweb/tpl/update_location.tpl b/gui/bweb/tpl/update_location.tpl
new file mode 100644 (file)
index 0000000..75adcba
--- /dev/null
@@ -0,0 +1,65 @@
+<br/>
+ <div class='titlediv'>
+  <h1 class='newstitle'>Update media location</h1>
+ </div> 
+ <div class="bodydiv">
+   <form action='?' method='get'>
+    <table id='id<TMPL_VAR NAME=ID>'></table>
+    New location : <select class='formulaire' name='newlocation'>
+   <TMPL_LOOP NAME=db_locations>
+      <option id='loc_<TMPL_VAR NAME=location>' value='<TMPL_VAR NAME=location>'><TMPL_VAR NAME=location></option>
+   </TMPL_LOOP>
+  </select>
+  <input type="image" name='action' value='save_location' src='/bweb/apply.png'>
+   </form>
+ </div>
+
+<script type="text/javascript" language="JavaScript">
+
+var header = new Array("Volume Name", "Location", "Select");
+
+var data = new Array();
+var chkbox;
+
+<TMPL_LOOP NAME=medias>
+chkbox = document.createElement('INPUT');
+chkbox.type  = 'checkbox';
+chkbox.value = '<TMPL_VAR name=volumename>';
+chkbox.name  = 'media';
+chkbox.checked = 1;
+
+data.push( new Array(
+"<TMPL_VAR NAME=volumename>",
+"<TMPL_VAR NAME=location>",
+chkbox
+ )
+);
+</TMPL_LOOP>
+
+nrsTable.setup(
+{
+ table_name:     "id<TMPL_VAR NAME=ID>",
+ table_header: header,
+ table_data: data,
+ up_icon: up_icon,
+ down_icon: down_icon,
+ prev_icon: prev_icon,
+ next_icon: next_icon,
+ rew_icon:  rew_icon,
+ fwd_icon:  fwd_icon,
+// natural_compare: false,
+ even_cell_color: even_cell_color,
+ odd_cell_color: odd_cell_color, 
+ header_color: header_color,
+ page_nav: true,
+ padding: 3,
+// disable_sorting: new Array(5,6)
+ rows_per_page: rows_per_page
+}
+);
+
+<TMPL_IF qnewlocation>
+ document.getElementById('loc_' + <TMPL_VAR qnewlocation>).selected=true;
+</TMPL_IF>
+
+</script>
diff --git a/gui/bweb/tpl/update_media.tpl b/gui/bweb/tpl/update_media.tpl
new file mode 100644 (file)
index 0000000..2dc7416
--- /dev/null
@@ -0,0 +1,159 @@
+<br/>
+<div class='titlediv'>
+ <h1 class='newstitle'> Update media <TMPL_VAR volumename></h1>
+</div>
+<div class='bodydiv'>
+  <form name='form1' action="?" method='GET'>
+   <table>
+    <tr><td>Volume Name:</td>
+        <td><input type='text' name='media' class='formulaire' value='<TMPL_VAR volumename>' title='Change this to update an other media'>
+        </td>
+    </tr>
+    <tr><td>Pool:</td>
+        <td><select name='pool' class='formulaire'>
+<TMPL_LOOP db_pools>
+             <option value='<TMPL_VAR name>'><TMPL_VAR name></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td>Status:</td>
+        <td><select name='volstatus' class='formulaire'>
+           <option value='Append'>Append</option>
+           <option value='Archive'>Archive</option>
+           <option value='Disabled'>Disabled</option>
+           <option value='Cleaning'>Cleaning</option>
+           <option value='Error'>Error</option>
+          <option value='Full'>Full</option>
+           <option value='Read-Only'>Read-Only</option>
+           <option value='Used'>Used</option>
+           </select>
+        </td>
+    </tr>
+
+    <tr><td>Slot:</td>
+        <td> 
+          <input class='formulaire' type='text' 
+                 name='slot' value='<TMPL_VAR slot>'>
+        </td>
+    </tr>
+
+    <tr><td>InChanger Flag:</td>
+        <td> 
+          <input class='formulaire' type='checkbox' 
+               name='inchanger' <TMPL_IF inchanger>checked</TMPL_IF>>
+        </td>
+    </tr>
+
+    <tr><td> Location : </td>
+        <td><select name='location' class='formulaire'>
+        <option value=''></option>
+  <TMPL_LOOP db_locations>
+      <option value='<TMPL_VAR location>'><TMPL_VAR location></option>
+  </TMPL_LOOP>
+    </select>
+        </td>
+    </tr>
+    <tr><td> Retention period: </td>
+        <td>
+          <input class='formulaire' type='text' title='ex: 3 days, 1 month'
+               name='volretention' value='<TMPL_VAR volretention>'>
+        </td>
+    </tr>
+    <tr><td> Use duration: </td>
+        <td>
+          <input class='formulaire' type='text' title='ex: 3 days, 1 month'
+               name='voluseduration' value='<TMPL_VAR voluseduration>'>
+        </td>
+    </tr>
+    <tr><td> Max Jobs: </td>
+        <td>
+          <input class='formulaire' type='text' title='ex: 10'
+               name='maxvoljobs' value='<TMPL_VAR maxvoljobs>'>
+        </td>
+    </tr>
+    <tr><td> Max Files: </td>
+        <td>
+          <input class='formulaire' type='text' title='ex: 10000'
+               name='maxvolfiles' value='<TMPL_VAR maxvolfiles>'>
+        </td>
+    </tr>
+    <tr><td> Max Bytes: </td>
+        <td>
+          <input class='formulaire' type='text' title='ex: 10M, 11G'
+               name='maxvolbytes' value='<TMPL_VAR maxvolbytes>'>
+        </td>
+    </tr>
+    <tr><td>Recycle Pool:</td>
+        <td><select name='poolrecycle' class='formulaire'>
+<TMPL_LOOP db_pools>
+             <option value='<TMPL_VAR name>'><TMPL_VAR name></option>
+</TMPL_LOOP>
+           </select>
+        </td>
+    </tr>
+    <tr><td> Comment: </td>
+        <td>
+          <input class='formulaire' type='text' title='a comment'
+               name='comment' value='<TMPL_VAR comment>'>
+        </td>
+    </tr>
+
+    </table>
+<table>
+ <td>
+ <label>
+  <input type="image" name='action' value='do_update_media' src='/bweb/apply.png'> Apply
+  </label>
+  <label>
+  <input type="image" name='action' title='Update from pool'
+    value='update_from_pool' src='/bweb/update.png'> Update from pool
+  </label>
+ </form>
+ </td>
+ <td>
+  <form action='?' method='GET'>
+   <input type='hidden' name='pool' value='<TMPL_VAR poolname>'>
+   <label>
+    <input type="image" name='action' value='media'
+     src='/bweb/zoom.png'>View Pool
+   </label>
+  </form>
+ </td>
+</table>
+</div>
+
+<script type="text/javascript" language='JavaScript'>
+var ok=1;
+for (var i=0; ok && i < document.form1.pool.length; ++i) {
+   if (document.form1.pool[i].value == '<TMPL_VAR poolname>') {
+      document.form1.pool[i].selected = true;
+      ok=0;
+   }
+}
+
+ok=1;
+for (var i=0; ok && i < document.form1.pool.length; ++i) {
+   if (document.form1.poolrecycle[i].value == '<TMPL_VAR poolrecycle>') {
+      document.form1.poolrecycle[i].selected = true;
+      ok=0;
+   }
+}
+
+ok=1;
+for (var i=0; ok && i < document.form1.location.length; ++i) {
+   if (document.form1.location[i].value == '<TMPL_VAR location>') {
+      document.form1.location[i].selected = true;
+      ok=0;
+   }
+}
+
+ok=1;
+for (var i=0; ok && i < document.form1.volstatus.length; ++i) {
+   if (document.form1.volstatus[i].value == '<TMPL_VAR volstatus>') {
+      document.form1.volstatus[i].selected = true;
+      ok=0;
+   }
+}
+
+</script>