#!/usr/bin/perl
#
# Copyright (c) 2009 Erik Inge Bolsø, Redpill Linpro AS
#
# 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; version 2 dated June,
# 1991.
#
# 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.

=pod

=encoding UTF-8

=head1 NAME

zimbra_ - Plugin to monitor all sorts of Zimbra statistics

=head1 APPLICABLE SYSTEMS

Zimbra 5+ with zmstat statistics enabled.

Text::CSV_XS (perl-Text-CSV_XS from EPEL, for example)

=head1 CONFIGURATION

Add this to the relevant munin-node config file:

 [zimbra*]
 group zimbra

The following environment variables are used by this plugin:

=over 4

=item csvpath

Path to zmstat csv files (default /opt/zimbra/zmstat)

=back

=head1 BUGS/GOTCHAS

Only reads latest value from the csv, which may be a "last 30 seconds"
or "last minute" value, so not a representative "last five minutes" value.
The original Zimbra stat charts often use a moving average of some sort.

=head1 AUTHOR

Erik Inge Bolsø <knan@redpill-linpro.com>, Redpill Linpro AS

=head1 COPYRIGHT

Copyright (c) 2009 Erik Inge Bolsø, Redpill Linpro AS

All rights reserved. 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; version 2
dated June, 1991.

=head1 MAGIC MARKERS

 #%# family=contrib
 #%# capabilities=autoconf suggest

=cut

use strict;
use warnings;

use Fcntl;
use Tie::File;

my $ret = "";

if (!eval "require Text::CSV_XS;") {
        $ret = "No Text::CSV_XS";
}

my $csvpath = ($ENV{'csvpath'} || '/opt/zimbra/zmstat');

# The possible measurements
my %ops =
    (
     'client_active_connections'
     => {
         'vlabel'   => 'connections',
         'title'    => "Client active connections",
         'info'     => "Mailboxd Active Connections by Client Protocol according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'imap',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'imap_conn',
           },
           {
           'label'    => 'imap_ssl',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'imap_ssl_conn',
           },
           {
           'label'    => 'pop3',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'pop_conn',
           },
           {
           'label'    => 'pop3_ssl',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'pop_ssl_conn',
           }, ],
        },
     'client_request_rate'
     => {
         'vlabel'   => 'requests/min',
         'title'    => "Client request rate",
         'info'     => "Mailboxd Request Rate by Client Protocol according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'soap',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'soap_count',
           },
           {
           'label'    => 'imap',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'imap_count',
           },
           {
           'label'    => 'pop3',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'pop_count',
           }, ],
        },
     'client_response_time'
     => {
         'vlabel'   => 'ms',
         'title'    => "Client response time",
         'info'     => "Mailboxd Response Time by Client Protocol according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'soap',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'soap_ms_avg',
           },
           {
           'label'    => 'imap',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'imap_ms_avg',
           },
           {
           'label'    => 'pop3',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'pop_ms_avg',
           }, ],
        },
     'connpool_latency'
     => {
         'vlabel'   => 'latency (ms)',
         'title'    => "Connection pool latency",
         'info'     => "Mailboxd connection pool get latencies according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'database',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'db_conn_ms_avg',
           },
           {
           'label'    => 'ldap',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'ldap_dc_ms_avg',
           }, ],
        },
     'jvm_heap_free'
     => {
         'vlabel'   => 'bytes',
         'title'    => "JVM heap free",
         'info'     => "Mailboxd JVM Heap Free according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'total',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'heap_free',
           },
           {
           'label'    => 'ps_old_gen',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_ps_old_gen_free',
           },
           {
           'label'    => 'cms_old_gen',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_cms_old_gen_free',
           },
           {
           'label'    => 'tenured_gen',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_tenured_gen_free',
           },
           {
           'label'    => 'train_gen',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_train_gen_free',
           },
           {
           'label'    => 'ps_eden',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_ps_eden_space_free',
           },
           {
           'label'    => 'ps_survivor',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_ps_survivor_space_free',
           },
           {
           'label'    => 'par_eden',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_par_eden_space_free',
           },
           {
           'label'    => 'par_survivor',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_par_survivor_space_free',
           },
           {
           'label'    => 'eden',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_eden_space_free',
           },
           {
           'label'    => 'survivor',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_survivor_space_free',
           }, ],
        },
     'jvm_heap_used'
     => {
         'vlabel'   => 'bytes',
         'title'    => "JVM heap used",
         'info'     => "Mailboxd JVM Heap Used according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'total',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'heap_used',
           },
           {
           'label'    => 'ps_old_gen',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_ps_old_gen_used',
           },
           {
           'label'    => 'cms_old_gen',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_cms_old_gen_used',
           },
           {
           'label'    => 'tenured_gen',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_tenured_gen_used',
           },
           {
           'label'    => 'train_gen',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_train_gen_used',
           },
           {
           'label'    => 'ps_eden',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_ps_eden_space_used',
           },
           {
           'label'    => 'ps_survivor',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_ps_survivor_space_used',
           },
           {
           'label'    => 'par_eden',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_par_eden_space_used',
           },
           {
           'label'    => 'par_survivor',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_par_survivor_space_used',
           },
           {
           'label'    => 'eden',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_eden_space_used',
           },
           {
           'label'    => 'survivor',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_survivor_space_used',
           }, ],
        },
     'jvm_major_gc_count'
     => {
         'vlabel'   => 'Count pr ${graph_period}',
         'title'    => "JVM major GC count",
         'info'     => "Mailboxd JVM Major GC Count according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'major',
           'type'     => 'DERIVE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'gc_major_count',
           }, ],
        },
     'jvm_major_gc_time'
     => {
         'vlabel'   => 'Time (ms) pr ${graph_period}',
         'title'    => "JVM major GC time",
         'info'     => "Mailboxd JVM Major GC Time according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'major',
           'type'     => 'DERIVE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'gc_major_ms',
           }, ],
        },
     'jvm_minor_gc_count'
     => {
         'vlabel'   => 'Count pr ${graph_period}',
         'title'    => "JVM minor GC count",
         'info'     => "Mailboxd JVM Minor GC Count according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'minor',
           'type'     => 'DERIVE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'gc_minor_count',
           }, ],
        },
     'jvm_minor_gc_time'
     => {
         'vlabel'   => 'Time (ms) pr ${graph_period}',
         'title'    => "JVM minor GC time",
         'info'     => "Mailboxd JVM Minor GC Time according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'minor',
           'type'     => 'DERIVE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'gc_minor_ms',
           }, ],
        },
     'jvm_permgen'
     => {
         'vlabel'   => 'bytes',
         'title'    => "JVM Perm Gen",
         'info'     => "Mailboxd JVM Permanent Generation and Code Cache according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'ps_perm_gen',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_ps_perm_gen_used',
           },
           {
           'label'    => 'perm_gen',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_perm_gen_used',
           },
           {
           'label'    => 'cms_perm_gen',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_cms_perm_gen_used',
           },
           {
           'label'    => 'code_cache',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_code_cache_used',
           },
           {
           'label'    => 'perm_gen_shared_ro',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_perm_gen_[shared-ro]_used',
           },
           {
           'label'    => 'perm_gen_shared_rw',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_perm_gen_[shared-rw]_used',
           },
           {
           'label'    => 'ps_perm_gen_free',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_ps_perm_gen_free',
           },
           {
           'label'    => 'perm_gen_free',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_perm_gen_free',
           },
           {
           'label'    => 'cms_perm_gen_free',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_cms_perm_gen_free',
           },
           {
           'label'    => 'code_cache_free',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_code_cache_free',
           },
           {
           'label'    => 'perm_gen_shared_ro_free',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_perm_gen_[shared-ro]_free',
           },
           {
           'label'    => 'perm_gen_shared_rw_free',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mpool_perm_gen_[shared-rw]_free',
           }, ],
        },
     'lmtp_throughput'
     => {
         'vlabel'   => 'bytes/min',
         'title'    => "LMTP throughput",
         'info'     => "Mailboxd LMTP Throughput according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'received',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'lmtp_rcvd_bytes',
           },
           {
           'label'    => 'delivered',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'lmtp_dlvd_bytes',
           }, ],
        },
     'lmtp_delivery_rate'
     => {
         'vlabel'   => 'msgs/min',
         'title'    => "LMTP delivery rate",
         'info'     => "Mailboxd LMTP Delivery Rate according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'received',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'lmtp_rcvd_msgs',
           },
           {
           'label'    => 'delivered',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'lmtp_dlvd_msgs',
           },
           {
           'label'    => 'rcvd_rcpt',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'lmtp_rcvd_rcpt',
           'info'     => 'received messages * recipients',
           }, ],
        },
     'lucene_cachehit'
     => {
         'vlabel'   => 'hitrate %',
         'title'    => "Lucene cache hitrate",
         'info'     => "Mailboxd Lucene IndexWriterCache hitrate according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'total',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'idx_wrt_opened',
           'csvfield2'=> 'idx_wrt_opened_cache_hit',
           'graph'    => 'off'
           },
           {
           'label'    => 'hit',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'idx_wrt_opened_cache_hit',
           'draw'     => 'AREA',
           'cdef'     => 'hit,total,/,100,*'
           }, ],
        },
     'lucene_io'
     => {
         'vlabel'   => 'bytes',
         'title'    => "Lucene I/O",
         'info'     => "Mailboxd lucene I/O according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'write',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'idx_bytes_written',
           },
           {
           'label'    => 'read',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'idx_bytes_read',
           }, ],
        },
     'lucene_writers'
     => {
         'vlabel'   => 'writers',
         'title'    => "Lucene index writers",
         'info'     => "Mailboxd dirty lucene index writers according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'writers',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'idx_wrt_avg',
           }, ],
        },
     'mailbox_add_latency'
     => {
         'vlabel'   => 'latency (ms)',
         'title'    => "Mailbox add latency",
         'info'     => "Mailboxd Mailbox Add Latency (Delivery Speed) according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'latency',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mbox_add_msg_ms_avg',
           }, ],
        },
     'mailbox_add_rate'
     => {
         'vlabel'   => 'msgs/min',
         'title'    => "Mailbox add rate",
         'info'     => "Mailboxd Mailbox Add Rate (Delivery Rate) according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'adds',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mbox_add_msg_count',
           }, ],
        },
     'mailbox_cachehit'
     => {
         'vlabel'   => 'hitrate %',
         'title'    => "Mailbox cache hitrate",
         'info'     => "Mailboxd Mailbox Cache hitrate according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'hit',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mbox_cache',
           }, ],
        },
     'mailbox_itemblob_cachehit'
     => {
         'vlabel'   => 'hitrate %',
         'title'    => "Mailbox item/blob cache",
         'info'     => "Mailboxd Mailbox Item/Blob Cache hitrate according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'blob',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mbox_msg_cache',
           },
           {
           'label'    => 'metadata',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mbox_item_cache',
           }, ],
        },
     # what does this actually measure? Hovers around 1 on an idle test server.
     'mailbox_get_count'
     => {
         'vlabel'   => 'count',
         'title'    => "Mailbox get count",
         'info'     => "Mailboxd Mailbox Get Count according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'get',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mbox_get_count',
           }, ],
        },
     'mailbox_get_latency'
     => {
         'vlabel'   => 'latency (ms)',
         'title'    => "Mailbox get latency",
         'info'     => "Mailboxd Mailbox Get Latency according to zmstat/mailboxd.csv",
         'fields'   => [ {
           'label'    => 'latency',
           'type'     => 'GAUGE',
           'csv'      => 'mailboxd.csv',
           'csvfield' => 'mbox_get_ms_avg',
           }, ],
        },
     'postfix_queue'
     => {
         'vlabel'   => 'Messages queued',
         'title'    => "Postfix messages queued",
         'info'     => "Postfix messages queued according to zmstat/mtaqueue.csv",
         'fields'   => [ {
           'label'    => 'messages',
           'type'     => 'GAUGE',
           'csv'      => 'mtaqueue.csv',
           'csvfield' => 'requests',
           }, ],
         },
     'process_cpu'
     => {
         'vlabel'   => 'percent cpu',
         'title'    => "Process CPU usage",
         'info'     => "Process CPU usage according to zmstat/proc.csv",
         'fields'   => [ {
           'label'    => 'mailbox',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'mailbox-total-cpu',
           },
           {
           'label'    => 'mysql',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'mysql-total-cpu',
           },
           {
           'label'    => 'convertd',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'convertd-total-cpu',
           },
           {
           'label'    => 'ldap',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'ldap-total-cpu',
           },
           {
           'label'    => 'postfix',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'postfix-total-cpu',
           },
           {
           'label'    => 'amavis',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'amavis-total-cpu',
           },
           {
           'label'    => 'clam',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'clam-total-cpu',
           },
           {
           'label'    => 'stats',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'stats-total-cpu',
           }, ],
        },
     'process_mem_total'
     => {
         'vlabel'   => 'MB',
         'title'    => "Process Total Memory",
         'info'     => "Process Total memory usage according to zmstat/proc.csv",
         'fields'   => [ {
           'label'    => 'mailbox',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'mailbox-totalMB',
           },
           {
           'label'    => 'mysql',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'mysql-totalMB',
           },
           {
           'label'    => 'convertd',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'convertd-totalMB',
           },
           {
           'label'    => 'ldap',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'ldap-totalMB',
           },
           {
           'label'    => 'postfix',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'postfix-totalMB',
           },
           {
           'label'    => 'amavis',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'amavis-totalMB',
           },
           {
           'label'    => 'clam',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'clam-totalMB',
           },
           {
           'label'    => 'stats',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'stats-totalMB',
           }, ],
        },
     'process_mem_rss'
     => {
         'vlabel'   => 'MB',
         'title'    => "Process Resident Memory",
         'info'     => "Process resident memory (RSS) according to zmstat/proc.csv",
         'fields'   => [ {
           'label'    => 'mailbox',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'mailbox-rssMB',
           },
           {
           'label'    => 'mysql',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'mysql-rssMB',
           },
           {
           'label'    => 'convertd',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'convertd-rssMB',
           },
           {
           'label'    => 'ldap',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'ldap-rssMB',
           },
           {
           'label'    => 'postfix',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'postfix-rssMB',
           },
           {
           'label'    => 'amavis',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'amavis-rssMB',
           },
           {
           'label'    => 'clam',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'clam-rssMB',
           },
           {
           'label'    => 'stats',
           'type'     => 'GAUGE',
           'csv'      => 'proc.csv',
           'csvfield' => 'stats-rssMB',
           }, ],
        },
    );

# Config subroutine
sub config {
    my $action = shift;
    if (!(exists $ops{$action})) { die "wrong symlinked name, $action is not implemented\n"; }
    print <<EOF;
graph_args --base 1000 -l 0
graph_vlabel $ops{$action}->{'vlabel'}
graph_title $ops{$action}->{'title'}
graph_category mail
graph_info $ops{$action}->{'info'}
EOF

    my $tmpfield = $ops{$action}->{'fields'};
    foreach my $field ( @$tmpfield )
    {
      my $label = $field->{'label'};
      print "$label.label $label\n";
      print "$label.type $field->{'type'}\n";
      print "$label.min 0\n";
      if (exists $field->{'graph'}) { print "$label.graph $field->{'graph'}\n"; }
      if (exists $field->{'info'}) { print "$label.info $field->{'info'}\n"; }
      if (exists $field->{'draw'}) { print "$label.draw $field->{'draw'}\n"; }
      if (exists $field->{'cdef'}) { print "$label.cdef $field->{'cdef'}\n"; }
    }
}

my $op;

if ($0 =~ /zimbra_([\w\d_]+)$/)
{
  $op = $1;
}

if ($ARGV[0]) {
    if ($ARGV[0] eq "config") {
        if ($op) {
            &config ($op);
        } else {
            die ("Can't run config without a symlinked name\n");
        }
    } elsif ($ARGV[0] eq "autoconf") {
        if ($ret ne "") {
          print "no ($ret)\n";
        }
        elsif (chdir $csvpath)
        {
          print "yes\n";
        }
        else
        {
          print "no (chdir to $csvpath failed)\n";
        }
    } elsif ($ARGV[0] eq "suggest") {
        foreach my $key ( keys %ops )
        {
          print "$key\n";
        }
    }
    exit 0;
}

# We won't run this without parameters.
die ("Can't run without a symlinked name\n") if $0 =~ /zimbra_$/;

my @cached_csvfields = ();

my $tmpfield = $ops{$op}->{'fields'};
foreach my $field ( @$tmpfield )
{
  my $label = $field->{'label'};
  my $csv = Text::CSV_XS->new ( { 'allow_whitespace' => 1 } );
  my $error;

  if (tie my @file, 'Tie::File', $csvpath . "/" . $field->{'csv'}, mode => O_RDONLY)
  {
    # parse the csv header line for the interesting field
    my $status = $csv->parse($file[0]);
    my @csvfields = $csv->fields();
    my $csvindex = 0; $csvindex++ until $csvindex > $#csvfields or $csvfields[$csvindex] eq $field->{'csvfield'};
    if ($csvindex > $#csvfields) { $error = 1; goto FIELDERR; }

    my $csvindex2;
    if (exists $field->{'csvfield2'})
    {
      $csvindex2 = 0; $csvindex2++ until $csvindex2 > $#csvfields or $csvfields[$csvindex2] eq $field->{'csvfield2'};
      if ($csvindex2 > $#csvfields) { $error = 1; goto FIELDERR; }
    }

    unless ($#cached_csvfields > -1)
    {
      # blindly use last line of the csv, for now
      $status = $csv->parse($file[-1]);

      @cached_csvfields = $csv->fields();
    }
    # empty csv field => undef
    if ($cached_csvfields[$csvindex] eq "") { $error = 1; goto FIELDERR; }

    if (defined $csvindex2)
    {
      print "$label.value " . ( $cached_csvfields[$csvindex] + $cached_csvfields[$csvindex2] ). "\n";
    } else {
      print "$label.value " . $cached_csvfields[$csvindex] . "\n";
    }
  } else { $error = 1; }

FIELDERR:
  if ($error) {
    print "$label.value UNDEF\n" ;
  }
}

