#!/usr/bin/perl

# Author: Martin Fuerstenau, Oce Printing Systems
#         martin.fuerstenau_at_oce.com or Martin.fuerstenau_at_nagiossw.org
#
# Date:   22 Jan 2009
# 
# TOPdesk (http://www.topdesk.com) is a service management tool owned and developed by 
# TOPdesk, Postbus 559, 2600 AN Delft, Netherlands
#
# Purpose and features of the program:
#
# - Submitting incidents (trouble tickets) to TOPdesk
#
# - Placing an acknowledge together with a comment containing the indicent number and a 
#   hyperlink to the incident ticket in Nagios. Further notification fromnagios will
#   be suppressed
#
# - Can handle more than one TOPdesk server
#
# - Can close/complete incidents
#   - Based on a timeframe
#   - Everytime
#   - Exeption: The file with the timestamp and the TOPdesk UNID has been deleted
#     (see below)
#   - Decision for close/complete is based on the TOPdesk Server
#
# - Default mappings for duration (Severity)
#   - Host:
#     DOWN        = Severity 1
#     UNREACHABLE = Severity 3
#   - Service:
#     CRITICAL = Severity 1
#     WARNING  = Severity 2
#     UNKNOWN  = Severity 3
#
# - Mappings can be overritten with -t
#   - Form:
#     "CRITICAL=1 WARNING=3 down=2"
#   - Lowercase letters will be automatically converted into uppercase ones because Nagios is 
#     delivering uppercase ones.
#   - Everything can be replaced from one mapping (for example CRITICAL) to all mappings
#
#
# History and Changes:
# 
# - 22 Jan 2009 Version 1
#    - First released version
#      For change history of all other 1.x versions see History and changes in a 1.x version.
#
# - 18 Jul 2017 Version 1.7.4
#   - This was the last 1.x version
#
#
# - 21 Mar 2018 Version 2.0.0
#
#   - Complete rework for Topdesk 7.11 API instead of using URLs
#   - Removed --version ($TD_version) option
#   - New routines for Login/Logout
#   - Rewriten create_incident() and modify_incident()
#   - Removed complete_create_incident()
#   - Removed -n because the notes field doesn't exist anymore
#   - Removed configuration object ($TD_object). Not needed
#   - Removed soortmeldingid - Incident Type - because we do create
#     only incidents
#   - Change variable $TD_input to $TD_entryType for better readability
#   - In the past a clear userfriendly entry could be used for the caller. But because
#     the user is normally a registered user in Topdesk the user can't be called by "caller" (and clear name).
#     It can only be called by callerLookup which need the UNID (ID in datababase). The UNID is in
#     API calls named as ID and a long alphanumerical not self explaining string. Because this can't be stored 
#     easily in hashes etc. the definition has been outsourced to .ini files. 
#
#     The name of the .ini file will be always in the format topdeskhost.domain.ini
#
#     Because some other definitions will also be referenced by UNID these mappings are also defined in the .ini file.
#
#     These definitions are:
#     - caller
#     - Entry type (Alert, WEB, Phone etc.)
#     - Duration (severity)
#     - Operator Groups
#
#     To have all user defineable values in one place all definitions stored in hashes in the old program
#     will be stored in the .ini files now.
#   - New option --config_dir if the config is stored in a non default location.
#   - Rewritten time stamp offset. Now acceptiing negative values for timezones west of Greenwich
#   - Removed free logic field support. This is much more complex in new Topdesk versions and can be
#     used for various content. So a general solution is not possible here.
#   - Replaced -R or --recover-status="text string" by --processing-status because it is
#     the status field from the Prosessing section.
#   - Option -r|--ready was changed to --close. The values for complete or close has to be stored 
#     in your config file and it must be allowed by Topdesk administration to do so.
#   - Changed $TD_incident_id to $TD_incident_number. It's more correct.
#   - Removed "Always complete or close the incident". This part was nonsense ;-)
#   - Removed -T|--time for automatically close/complete an incident after a given time. 
#     Doesn't fit compliance requirement and doesn't make sense anymore.
#
#
# How it works:
# 
# Read the code. There is a lot of comments in it.
#
#
# Setup:
# In this script you only have to setup some variables and hashes to fit your requirements.
# 
# $tmp_dir="/tmp";                           # Directory to store the UNID and the timestamp temporarily
# $nag_pipe="/var/spool/nagios/nagios.cmd";  # The nagios command pipe
# $TD_status_def="2";                        # 1 indicates a first line incident, 2 indicates
#
# In Nagios you have to 
#
# - define a notification command
#
#   # 'notify-by-topdesk-test' command definition
#   define command{
#   command_name    notify-by-topdesk-test
#   command_line    handle_TD_incident -U http://tdserver1.mycompany.com -N $NOTIFICATIONTYPE$ -H $HOSTNAME$ -S "$SERVICEDESC$" -C 'Monitoring Tools' -c 'Nagios, Cacti, ...' -s $SERVICESTATE$ -M "$SERVICEOUTPUT$"
#   }
#
# - add a contact for the host/service for TOPDesk
#   define contact{
#           contact_name                        topdesk_test
#           alias                               topdesk_test
#           service_notification_period         24x7
#           host_notification_period            24x7
#           service_notification_options        c,w,u,r
#           host_notification_options           d,u,r
#           service_notification_commands       notify-by-topdesk-test
#           host_notification_commands          host-notify-by-topdesk-test
#           email                               dummy or address from the caller field
#           }
#
# - add the contact to the appopriate contactgroup for notification
# 
# Synopsis (not complete):
# 
# handle_TD_incident -U|--url <TOPdesk base URL> -H|--host <host> -S|--service <service> -N|--notificationtype <Nagios notificationtype> -n|--notice <Notes> -b|--briefdescription <Brief Description> -M|--message <message> -C|--category <category> -c|--subcategory <subcategory> -k|--caller <Caller> -e|--entry <Entry> -s|--state <Nagios state> -o|--typeofcall <Incident or Security...> -l|--line <1=1stline call, 2=2ndline call> -O|--operator <operator group> -t|--severity <\"CRITICAL=2 WARNING=3 ...\"> -T|--time <Time in Minutes> -W|--wait <wait for retry> -w|--retry <retry interval> -m|--mail <email-address> -r|--ready
#
#----------------------------------------------------------------------

# For a better understanding:
# All variables belonging to Nagios are starting with nag_
# All variables belonging to TOPdesk are starting with TD_

use strict;

use Getopt::Long;
use Time::localtime;
use Date::Calc qw(:all);
use Net::Ping;
use REST::Client;
use MIME::Base64;
use Config::IniFiles;


#--- Start presets and declarations -------------------------------------

my $ProgName="handle_TD_incident";            # Name of program

my $config_dir;                               # Config file directory. Default is below

my $config_dir_def="/etc/nagios/plugin.conf.d/handle_TD_incident"; 
                                              
my $config;                                   # Needed for Config::IniFiles as a handle
my $config_file;                              # Stores the config file name

my $is_dead;                                  # Stores the ping result

my $timestamp=time();                         # Sets the Timestamp
                                              # - for acknowledge in Nagios
                                              # - for to be stored in the tempory file which contains 
                                              #   the timestamp of ack and the unid for the incident

my $TD_Timestamp;                             # Sets the timestamps for the actions in TOPdesk.
                                              # Otherwise you will not know when a message/action
                                              # took place.
my $TD_timestamp_offset;                      # Because Time_to_Dahandle_TD_incident.1.7.2te() uses UTC and localtime() is not
                                              # aware of Daylight Saving Time (DST) we nee a offset in seconds.
                                              
my $help;                                     # For printing the help message

my $mailer="/usr/sbin/sendmail -t";           # Mail command used
                                              
my $URL;                                      # Here we store the contructed URL to get
my $tmp_dir="/tmp";                           # Directory to store the UNID and the timestamp temporarily

my $NoA;                                      # Number of arguments handled over
                                              # the program

my $nag_pipe="/var/spool/nagios/nagios.cmd";  # The nagios command pipe

my $nag_host;                                 # The host causing the alert
my $nag_service;                              # The service causing the alert
my $nag_message;                              # Message submitted from Nagios
my $nag_state;                                # The state Nagios delivers

my $nag_notificationtype;                     # Nagios notification type. Can be:
                                              #
                                              # - PROBLEM (used)
                                              # - RECOVERY (used)
                                              # - ACKNOWLEDGEMENT (used)
                                              # - FLAPpingSTART (unused)
                                              # - FLAPpingSTOP (unused)
                                              # - FLAPpingDISABLED (unused)
                                              # - DOWNTIMESTART (unused)
                                              # - DOWNTIMEEND (unused)
                                              # - DOWNTIMECANCELLED (unused)

my $nag_contact;                              # - Nagios Contact for TOPdesk. Will be filled later on
                                              #   automatically in an array of the same name

my $nag_contact_email;                        # - Nagios Contact email. If the Topdesk host
                                              #   cannot be reached a email with the content
                                              #   of the ticket will be sent to this mail address
                                              #   with an alert. Maybe the calldesk or something
                                              #   like that.


my $TD_entryType;                             # Entry field in TOPdesk
my $TD_entryType_UNID;                        # Entry field in TOPdesk Unified Identifier

my $nag_TD_sev_mapping;                       # Contains an alternative mapping in the form
                                              # "CRITICAL=1 WARNING=3" etc.
                                              # Lowercase letters will be converted to uppercase ones
                                              # You have only to add mappings, which should be 
                                              # different from standard mapping
                                              # Mapping should be handled over as a string so don't
                                              # omit the quotes

my $nag_TD_sev_map1st;                        # This is used in conjunction with severity mapping and
                                              # line mapping. 

my %nag_TD_sev_mapping;                       # $nag_TD_sev_mapping will be convert in a hash. Her
                                              # is it.

my @nag_TD_sev_mapping;                       # Used in conversion
my $nag_TD_sev_mapping_key;                   # Used in conversion too
my $nag_TD_sev_mapping_value;                 # Used in conversion too

my %nag_TD_status_linemap;                    # $nag_TD_status_linemap will be convert in a hash. Her
                                              # is it.

my @nag_TD_status_linemap;                    # Used in conversion
my $nag_TD_status_linemap_key;                # Used in conversion too
my $nag_TD_status_linemap_value;              # Used in conversion too

my $TD_OperatorGroup;                         # This is the operator group
my $TD_OperatorGroup_UNID;                    # This is the operator group Unified Identifier

my $TD_username;                              # Login-Name TopDeskServer
my $TD_password;                              # Password for Login-Name
my $TD_Auth_Token;                            # Will take the authorization token

my $TD_Rest_Client;                           # Will take REST API handle

my $TD_caller;                                # Caller
my $TD_caller_UNID;                           # Caller Unified Identifier

my $TD_wait="";                               # Time to wait in seconds if a host is not reachable
my $TD_wait_retry;                            # Time to wait retry interval in seconds
my $TD_wait_retry_def="10";                   # Time to wait retry interval in seconds (default)

my $TD_processing_status;                     # Contains the status value from the processing section
my $TD_processing_status_UNID;                # Contains the UNID of the status value from the processing section
                                              
my $TD_severity;                              # Topdesk field duration
                                              # Must contain the string 'Severity 1',
                                              # 'Severity 2','Severity 3' or 'Severity 4'
                                              # Due to the fact the Nagios only nows critical/down,
                                              # warning, unknown/unreachable
                                              # the use of all 4 is very limited.
my $TD_severity_UNID;                         # Topdesk field duration Unified Identifier

my $TD_sev_unmapped;                          # Contains the unmapped severity for linemapping,

my $TD_status;                                # 1 indicates a first line incident, 2 indicates
                                              # a second line incident.
my $TD_status_def="2";                        # The default

my $TD_complete_close;                        # Complete or close an incident

my $nag_TD_status_linemap="";                 # Contains an alternative line/severity mapping in the form
                                              # "s2=l1 s1=l1" etc.
                                              # Lowercase letters will be converted to uppercase ones
                                              # You have only to add mappings, which should be 
                                              # different from standard mapping
                                              # Mapping should be handled over as a string so don't
                                              # omit the quotes
                                              
my $TD_message;                               # Message submitted to Topdesk
my $TD_category;                              # Category handled over from nagios
my $TD_brief_desc;                            # Fills the field brief description
my $TD_subcategory;                           # Subcategory handled over from nagios
my $TD_incident_number;                       # The incident number get back from TOPdesk
my $TD_incident_number_UNID;                  # The incident number UNID get back from TOPdesk

my $TD_URL;                                   # TOPdesk server name in the form http://servername
                                              # or https://servername
my $TD_server;                                # TOPdesk server name
my @URL_BASE;

my $HTTP_headers;                             # Hash reference. Stores headers like Authorization,
                                              # Application type etc.
my $HTTP_Ret_Code;                            # We need it now in case we have a problem to 
                                              # to connect to topdesk while the host reachable but
                                              # the URL is not working

my $ping_prot_def="icmp";                     # Default protocol for ping.
my $ping_prot;                                # We have another protocol for ping?

my $OptMailMsg;                               # Optional mail message in case Topdesk is not reachable. This 
                                              # can be text like "Call 911" or "Better jump out the window"
                                              # or something else



#--- End presets --------------------------------------------------------

# First we have to fix  the number of arguments

$NoA=$#ARGV;

Getopt::Long::Configure('bundling');
GetOptions
	("b=s" => \$TD_brief_desc,        "briefdescription=s"  => \$TD_brief_desc,
         "C=s" => \$TD_category,          "category=s"          => \$TD_category,
	 "c=s" => \$TD_subcategory,       "subcategory=s"       => \$TD_subcategory,
	 "e=s" => \$TD_entryType,         "entry=s"             => \$TD_entryType,
         "h"   => \$help,                 "help"                => \$help,
	 "H=s" => \$nag_host,             "host=s"              => \$nag_host,
	 "k=s" => \$TD_caller,            "caller=s"            => \$TD_caller,
	 "l=s" => \$TD_status,            "line=s"              => \$TD_status,
	                                  "linemap=s"           => \$nag_TD_status_linemap,
	 "N=s" => \$nag_notificationtype, "notificationtype=s"  => \$nag_notificationtype,
	 "m=s" => \$nag_contact_email,    "mail=s"              => \$nag_contact_email,
	 "M=s" => \$nag_message,          "message=s"           => \$nag_message,
	 "O=s" => \$TD_OperatorGroup,     "operator=s"          => \$TD_OperatorGroup,
         "p=s" => \$TD_password,          "password=s"          => \$TD_password,
	                                  "close"               => \$TD_complete_close,
	                                  "processing-status=s" => \$TD_processing_status,
	 "s=s" => \$nag_state,            "state=s"             => \$nag_state,
	 "S=s" => \$nag_service,          "service=s"           => \$nag_service,
	 "t=s" => \$nag_TD_sev_mapping,   "severity=s"          => \$nag_TD_sev_mapping,
	                                  "sevmapfirst=s"       => \$nag_TD_sev_map1st,
         "u=s" => \$TD_username,          "user=s"              => \$TD_username,
	 "U=s" => \$TD_URL,               "url=s"               => \$TD_URL,
	 "w=s" => \$TD_wait_retry,        "waitretry=s"         => \$TD_wait_retry,
	                                  "ping=s"              => \$ping_prot,
	                                  "config_dir=s"        => \$config_dir,
                                          "optmailmsg=s"        => \$OptMailMsg,
	 "W=s" => \$TD_wait,              "wait=s"              => \$TD_wait);


# First of all test if it a call give by Nagios problem acknowledge 
# If yes get out of here

if ($nag_notificationtype eq "ACKNOWLEDGEMENT" )
   {
   exit 0;
   }

if ($nag_notificationtype eq "FLAPpingSTART" )
   {
   exit 0;
   }

if ($nag_notificationtype eq "FLAPpingSTOP" )
   {
   exit 0;
   }

if ($nag_notificationtype eq "FLAPpingDISABLED" )
   {
   exit 0;
   }

if ($nag_notificationtype eq "DOWNTIMESTART" )
   {
   exit 0;
   }

if ($nag_notificationtype eq "DOWNTIMEEND" )
   {
   exit 0;
   }

if ($nag_notificationtype eq "DOWNTIMECANCELLED" )
   {
   exit 0;
   }

# So now we check the neccessary arguments given to the script

# 1. Only help?

if ($help)
   {
   print_help();
   exit 0;
   }

# Right number of arguments (therefore NOA :-)) )

if ( $NoA == -1 )
   {
   print_usage();
   exit 1;
   }

# Do we have a URL?

if (!$TD_URL)
   {
   print "No URL for TOPDesk server given!\n\n";
   print_help();
   exit 1;
   }

#Is $OptMailMsg handled over via commandline?

if (!$OptMailMsg)
   {
   $OptMailMsg=" ";
   }

# Is $TD_status handled over via commandline? If not use default.

if (!$TD_status)
   {
   $TD_status=$TD_status_def;
   }

# Is $TD_wait handled over via commandline? If not use default. Same for retry interval.

if ($TD_wait)
   {

   # Because $TD_wait is in minutes we have to convert it to seconds for using
         
   $TD_wait = $TD_wait * 60;
   if (!$TD_wait_retry)
      {
      $TD_wait_retry=$TD_wait_retry_def;
      }

   if (!$nag_contact_email)
      {
      print "If -W is set you also has to enter a email address with -m!\n\n";
      print_help();
      exit 1;
      }
   }

if (!$TD_category)
   {
   print "No category for TOPDesk server given!\n\n";
   print_help();
   exit 1;
   }

if (!$TD_subcategory)
   {
   print "No sub category for TOPDesk server given!\n\n";
   print_help();
   exit 1;
   }

if (!$nag_host)
   {
   print "No host from Nagios server given!\n\n";
   print_help();
   exit 1;
   }

if (!$nag_state)
   {
   print "No state from Nagios given!\n\n";
   print_help();
   exit 1;
   }

if (!$nag_service)
   {
   if ($nag_state eq 'CRITICAL' || $nag_state eq 'WARNING' || $nag_state eq 'UNKNOWN')
      {
      print "No service from Nagios server given!\n\n";
      print_help();
      exit 1;
      }
   }

if ($nag_TD_sev_map1st)
   {
   if (length $nag_TD_status_linemap)
      {
      print "--sevmapfirst needs --linemap !\n\n";
      print_help();
      exit 1;
      }
   }

if (!$nag_message)
   {
   print "No message from Nagios given!\n\n";
   print_help();
   exit 1;
   }
else
   {
   # Remove HTML code
   $nag_message =~ s/<[Bb][Rr]>//g;
   }

if ($ping_prot)
   {
   $ping_prot =~ tr/A-Z/a-z/; 

   if ($ping_prot ne 'tcp' && $ping_prot ne 'udp' )
      {
      print "Unknow protocol for ping. Only icmp (only user root) ,tcp and udp are allowed!\n\n";
      print_help();
      exit 1;
      }
   }
else
   {
   $ping_prot=$ping_prot_def;
   }

# Well, well well ... here we set up the array with alternative mappings
# for the severity code. We use it later

if ($nag_TD_sev_mapping)
   {
   $nag_TD_sev_mapping = uc($nag_TD_sev_mapping);
   $nag_TD_sev_mapping =~ s/=/ /isog;
   $nag_TD_sev_mapping =~ s/\s+/ /isog;
   @nag_TD_sev_mapping = split(/ /, $nag_TD_sev_mapping);
   
   while(@nag_TD_sev_mapping)
        {
        $nag_TD_sev_mapping_key = shift(@nag_TD_sev_mapping);
        $nag_TD_sev_mapping_value = shift(@nag_TD_sev_mapping);
        $nag_TD_sev_mapping{$nag_TD_sev_mapping_key} = $nag_TD_sev_mapping_value;
        }
   
   }


# Now we map states from Nagios. If an alternative mapping is in the hash
# it will be used
# 
# Default mappings Host:
#
# DOWN        = Severity 1
# UNREACHABLE = Severity 3
#
# Default mappings Service:
#
# CRITICAL = Severity 1
# WARNING  = Severity 2
# UNKNOWN  = Severity 3

if ($nag_state eq 'CRITICAL' )
   {
   $TD_sev_unmapped="Severity 1";
   if ($nag_TD_sev_mapping{$nag_state})
      {
      $TD_severity="Severity ".$nag_TD_sev_mapping{$nag_state};
      }
   else
      {
      $TD_severity="Severity 1";
      }
   }

if ($nag_state eq 'DOWN')
   {
   $TD_sev_unmapped="Severity 1";
   if ($nag_TD_sev_mapping{$nag_state})
      {
      $TD_severity="Severity ".$nag_TD_sev_mapping{$nag_state};
      }
   else
      {
      $TD_severity="Severity 1";
      }
   }

if ($nag_state eq 'WARNING')
   {
   $TD_sev_unmapped="Severity 2";
   if ($nag_TD_sev_mapping{$nag_state})
      {
      $TD_severity="Severity ".$nag_TD_sev_mapping{$nag_state};
      }
   else
      {
      $TD_severity="Severity 2";
      }
   }

if ($nag_state eq 'UNREACHABLE')
   {
   $TD_sev_unmapped="Severity 3";
   if ($nag_TD_sev_mapping{$nag_state})
      {
      $TD_severity="Severity ".$nag_TD_sev_mapping{$nag_state};
      }
   else
      {
      $TD_severity="Severity 3";
      }
   }
   
if ($nag_state eq 'UNKNOWN')
   {
   $TD_sev_unmapped="Severity 3";
   if ($nag_TD_sev_mapping{$nag_state})
      {
      $TD_severity="Severity ".$nag_TD_sev_mapping{$nag_state};
      }
   else
      {
      $TD_severity="Severity 3";
      }
   }


# Another well, well well ... here we set up the array with alternative mappings
# for the line (1st or 2nd) and do the mapping depending ot the severity.

if ($nag_TD_status_linemap)
   {
   $nag_TD_status_linemap = uc($nag_TD_status_linemap);
   $nag_TD_status_linemap =~ s/=/ /isog;
   $nag_TD_status_linemap =~ s/\s+/ /isog;
   @nag_TD_status_linemap = split(/ /, $nag_TD_status_linemap);
   
   while(@nag_TD_status_linemap)
        {
        $nag_TD_status_linemap_key = shift(@nag_TD_status_linemap);

        if ($nag_TD_status_linemap_key !~ m/^s/i)
           {
           print "Line mapping not in an appropriate form. Please correct!\n\n";
           print_help();
           }

        # This is the trick. The severity is in the form "Severity 3" (see above). Because we change the s
        # to "Severity " we can use $TD_severity as key for %nag_TD_status_linemap later and will have the correct
        # line
        
        $nag_TD_status_linemap_key =~ s/s/Severity /isog;
           
        $nag_TD_status_linemap_value = shift(@nag_TD_status_linemap);

        if ($nag_TD_status_linemap_value !~ m/^l/isog)
           {
           print "Line mapping not in an appropriate form. Please correct!\n\n";
           print_help();
           }

        $nag_TD_status_linemap_value =~ s/l//isog;
        
        $nag_TD_status_linemap{$nag_TD_status_linemap_key} = $nag_TD_status_linemap_value;
        }

   if (!$nag_TD_sev_map1st)
      {
      $TD_status=$nag_TD_status_linemap{$TD_sev_unmapped};
      }
   else
      {
      $TD_status=$nag_TD_status_linemap{$TD_severity};
      }
   }

# So now we seperate the protocol and server name - we need it seperated for the following arrays

$TD_server=$TD_URL;

$TD_server=~s/\/\///isog;
@URL_BASE=split(/:/, $TD_server);

$TD_server=$URL_BASE[1];

# Setting the path for the config file
if (!defined($config_dir))
   {
   $config_dir=$config_dir_def; 
   }

# Setting the config file name
$config_file = $config_dir . "/" . $TD_server . ".cfg";

# And now we have to check for the configuration file and also check for a correct syntax

if( open(THIS_CONF,"<$config_file") )
  {
  close(THIS_CONF);

  $config = new Config::IniFiles( -file => $config_file);
      
  if(!defined($config))
    {
    print "Error in config file - please check the syntax in the config file\n";
    exit 2;
    }
  }   
else
  {
  print "Error - configuration file not found\n";
  exit 2;
  }

# Now we fill the variables with the values from the hashes because it is easier to handle 
# variables instead of hashes or arrays

# If the username is not handed over via commandline the default from the config file will be taken
if (!defined($TD_username))
   {
   $TD_username = $config->val('Login', "username");
   if (!defined($TD_username))
      {
      print "User name for login not set in config file and not handed over via command line\n";
      exit 2;
      }
   }

# If the password is not handed over via commandline the default from the config file will be taken
if (!defined($TD_password))
   {
   $TD_password = $config->val('Login', "userpass");
   if (!defined($TD_password))
      {
      print "Password for login not set in config file and not handed over via command line\n";
      exit 2;
      }
   }

# If the caller is not set set it to default

if (!defined($TD_caller))
   {
   $TD_caller = $config->val('Caller', "default");
   if (!defined($TD_caller))
      {
      print "Caller not set in config file and not handed over via command line\n";
      exit 2;
      }
   }
      
$TD_caller_UNID = $TD_caller;
   
# Convert spaces to underscores
$TD_caller_UNID =~ s/ /_/g;
  
# Get the caller UNID
$TD_caller_UNID = $config->val('Caller', "$TD_caller_UNID");

if (!defined($TD_caller_UNID))
   {
   print "Caller UNID for caller $TD_caller not set in config file\n";
   exit 2;
   }

# Set the processing status if handed over from command line

if (defined($TD_processing_status))
   {
   $TD_processing_status_UNID = $TD_processing_status;
      
   # Convert spaces to underscores
   $TD_processing_status_UNID =~ s/ /_/g;

   # Get the caller UNID
   $TD_processing_status_UNID = $config->val('ProcessingStatus', "$TD_processing_status_UNID");
   
   if (!defined($TD_processing_status_UNID))
      {
      print "Processing status UNID for $TD_processing_status not set in config file\n";
      exit 2;
      }
   }

# Is $TD_entryType handled over via commandline? If not use default.

if (!defined($TD_entryType))
   {
   $TD_entryType = $config->val('entryType', "default");
   if (!defined($TD_entryType))
      {
      print "Entry type not set in config file and not handed over via command line\n";
      exit 2;
      }
   }

$TD_entryType_UNID = $config->val('entryType', "$TD_entryType");

if (!defined($TD_entryType_UNID))
   {
   print "Entry type UNID for entry type $TD_entryType not set in config file\n";
   exit 2;
   }

# Getting the Nagios contact for setting the acknowledgement
$nag_contact = $config->val('Misc', "nag_contact");

# Make the topdesk time stamp.
$TD_Timestamp = $timestamp;

$TD_timestamp_offset = $config->val('Misc', "timestamp_offset");

if (!defined($TD_timestamp_offset))
   {
   print "Time stamp offset for Topdesk time stamp not set in config file\n";
   exit 2;
   }

# Timezone offset
$TD_Timestamp = $TD_Timestamp + $TD_timestamp_offset; 

# The values defiverd here are senseless. We only need DST (Daylight Saving Time)
# But it so we do not need another Perl module for getting DST

(my $year,my $month,my $day, my $hour,my $minute,my $sec,my $xx,my $yy,my $DST) = System_Clock();

if ($DST == 1)
   {
   $TD_Timestamp = $TD_Timestamp + 3600;
   }


($year,$month,$day,$hour,$minute,$sec) = Time_to_Date($TD_Timestamp);

$TD_Timestamp = sprintf("%02d %.3s %s %02d:%02d",$day,Month_to_Text($month),$year,$hour,$minute);

# Now we have to set up the right message to handle over to Topdesk

if ($nag_state eq 'DOWN' || $nag_state eq 'UNREACHABLE')
   {
   $TD_message="$TD_Timestamp  $TD_caller:  Host $nag_host reports to be $nag_state. - Message: $nag_message";
   }

if ($nag_state eq 'CRITICAL' || $nag_state eq 'WARNING' || $nag_state eq 'UNKNOWN')
   {
   $TD_message="$TD_Timestamp  $TD_caller:  Host $nag_host - Service $nag_service reports to be $nag_state. - Message: $nag_message";
   }

if (!defined($nag_contact))
   {
   print "Contact name for monitor system not set in config file\n";
   exit 2;
   }

# Now we test if the Topdesk Server is reachable
$is_dead=ping($TD_server);

# Now enough of the skirmish - let's get real
#--- Recover or incident? The main part  ------------------------------------

# OK or UP means that we have a recovery. Therefore we have to get the 
# previously saved incident ID together with the timestamp of saving.

if ($nag_state eq 'OK' || $nag_state eq 'UP' )
   {

   # If the Topdesk server is dead we have to exit
   
   if ( $is_dead eq "Dead" )
      {
      print "Topdesk server not reachable.\n";
      exit 0;
      }

   # Well lets do the recovery work
   
   $TD_incident_number=get_incident_id_tmp_file();
   
   # If NOF (NO File) is returned we have no tempfile. There we have no
   # incident number. Opposite to politicians we can do nothing
   # if we have no information
   
   if ( $TD_incident_number eq "NOF" )
      {
      print "No file with stored incident number found. Therefore we exit.\n";
      exit 0;
      }

   # Nesseary due to the fact that $TD_incident_number is the last element of a line from a file 
   # and therefore it contains a linefeed
   
   chomp($TD_incident_number);
   
   # In case if recovery: Completed, Closed ort nothing

   if (defined($TD_complete_close))
      {
      $TD_complete_close = "close";
      $TD_complete_close = $config->val('Close', "$TD_complete_close");
   
      if (!$TD_complete_close)
         {
         print "No valid value found for Completed or Closed.\n";
         exit 2;
         }
      }

   # So now if MAX_AGE handled over via commandline is less or equal $timediff
   # we can close or complete the ticket
   # Otherwise we will only add a comment

   $TD_Auth_Token=TD_login();

   modify_incident();

   TD_logout();
   exit 0;
   }
else
   {
      
   # If the Topdesk server is dead we have to set a comment and perform a loop
   # If the loop fails we have to exit

   if ( $is_dead eq "Dead" )
      {
      set_comment();

      if ( $TD_wait )
         {

         my $retry_counter;
         my $retry_counter_max = $TD_wait / $TD_wait_retry;
         
         for ($retry_counter = 1; $retry_counter <= $retry_counter_max ; $retry_counter++)
             {
             sleep $TD_wait_retry;

             $is_dead=ping($TD_server);

             if ( $is_dead eq "Alive" )
                {
                last;
                }
             }
         }

      if ( $is_dead eq "Dead" )
         {
         
         # If it is still dead we have to send an email for to the given
         # contact and die.
         
         shit_happens();
         exit 0;
         }
      }


   # Well now we will generate work for someone at the end of the food chain
   
   $TD_Auth_Token=TD_login();

   ($TD_incident_number_UNID, $TD_incident_number) =create_incident();

   store_incident_id();
   set_acknowledge();

   TD_logout();
   
   # This should never happen. But to be shure we wanna have a clean exit here
   exit;
   }

#--- Begin subroutines ------------------------------------------------------

sub TD_login()
    {
    my $result = "";
    my $Login_URL = $TD_URL . "/tas/api/login/operator";

    $HTTP_headers = {
                     Authorization => 'Basic '.  encode_base64($TD_username . ':' . $TD_password),
                     Accept => 'application/json', 
                    };

    $TD_Rest_Client = REST::Client->new();

    $TD_Rest_Client->GET($Login_URL, $HTTP_headers); 

    $HTTP_Ret_Code = $TD_Rest_Client->responseCode();
    
    if ( $HTTP_Ret_Code == 200 )
       {
       $result = $TD_Rest_Client->responseContent();
       }

    if ( $HTTP_Ret_Code == 401 )
       {
       print "Error: Invalid login credentials\n";
       exit 2;
       }

    if ( $HTTP_Ret_Code == 500 )
       {
       print "Error: An error occurred on the server.\n";
       shit_happens();
       exit 0;
       }
    return $result;
    }

sub TD_logout()
    {
    my $result = "";
    my $Logout_URL = $TD_URL . "/tas/api/logout";
    
    $HTTP_headers = {
                     Authorization => 'TOKEN id="'. $TD_Auth_Token . '"',
                     Accept => 'application/json', 
                    };

    $TD_Rest_Client->GET($Logout_URL, $HTTP_headers); 

    $HTTP_Ret_Code = $TD_Rest_Client->responseCode();

    if ( $HTTP_Ret_Code == 200 )
        {
        exit 0;
        }

    if ( $HTTP_Ret_Code == 401 )
       {
       print "Error: Invalid credentials. Logout not successfull.\n";
       exit 0;
       }

    if ( $HTTP_Ret_Code == 500 )
       {
       print "Error: An error occurred on the server. Logout not successfull.\n";
       exit 0;
       }
    }

sub create_incident()
    {
    
    my $result = "";
    my @result;
    my $request = "{ ";
    my $incident_UNID = "unknown";
    my $incident_number = "unknown";;
    
    # Unfortunately the value of the status has been changed
    # for the API from a number to a string. To avoid rewriting 
    # all code handling this we leave it unchanged in the rest of 
    # the code 
    
    my $TD_status_api;
    
    my $CreateIncident_URL = $TD_URL . "/tas/api/incidents";
    
    $HTTP_headers = {
                     Authorization => 'TOKEN id="'. $TD_Auth_Token . '"',
                     Accept => 'application/json', 
                    };

    # persoonid - Caller (Registered)
    $request = $request . "\"callerLookup\" : { \"id\" : \"" . $TD_caller_UNID . "\" },";
	
    # status - First line or second line incident - API: status
    if (!defined($TD_status))
       {
       print "Error (create incident): No information given for 1st or 2nd line incident.\n";
       exit 2;
       }
    else
       {
       if ( $TD_status == 1 )
          {
          $TD_status_api = "firstLine";
          }

       if ( $TD_status == 2 )
          {
          $TD_status_api = "secondLine";
          }
       $request = $request . "\"status\" : \"" . $TD_status_api . "\",";
       }
       
    # incident_domeinid - API: category
    if (!defined($TD_category))
       {
       print "Error (create incident): No category specified!\n";
       exit 2;
       }
    else
       {
       $request = $request . "\"category\" : { \"name\" : \"" . $TD_category . "\" },";
       }
	
    # incident_specid - API: subcategory
    if (!defined($TD_subcategory))
       {
       print "Error (create incident): No subcategory specified!\n";
       exit 2;
       }
    else
       {
       $request = $request . "\"subcategory\" : { \"name\" : \"" . $TD_subcategory . "\" },";
       }
	
    # verzoek - Request - Contains the message - API: request
    if (!defined($TD_message))
       {
       print "Error (create incident): No message from monitor given!\n";
       exit 2;
       }
    else
       {
       $request = $request . "\"request\": \"" . $TD_message . "\",";
       }

    # doorlooptijdi - Duration => Severity - overwrites default
    if (!defined($TD_severity))
       {
       print "Error (create incident): No severity defined!\n";
       exit 2;
       }
    else
       {
       $TD_severity_UNID = $TD_severity;

       # Convert spaces to underscores
       $TD_severity_UNID =~ s/ /_/g;
      
       $TD_severity_UNID = $config->val('durations', "$TD_severity_UNID");

       if (!defined($TD_severity_UNID))
          {
          print "Error (create incident): No severity UNID set in config file\n";
          exit 2;
          }
       $request = $request . "\"duration\" : { \"id\": \"" . $TD_severity_UNID . "\" },";
       }
	
    # soortbinnenkomstid - Entry - Default: WEB - API: entryType
    $request = $request . "\"entryType\" : { \"id\": \"" . $TD_entryType_UNID . "\" },";

    # korteomschrijving - Brief Description - API: briefDescription (optional)
    if (defined($TD_brief_desc))
       {
       $request = $request . "\"briefDescription\": \"" . $TD_brief_desc . "\",";
       }

    # actiedoorid - Operator (Second Line) - API: operator
    if (!defined($TD_OperatorGroup))
       {
       print "Error (create incident): No operator group defined!\n";
       exit 2;
       }
    else
       {
       $TD_OperatorGroup_UNID = $TD_OperatorGroup;

       # Convert spaces to underscores
       $TD_OperatorGroup_UNID =~ s/ /_/g;
      
       $TD_OperatorGroup_UNID = $config->val('OperatorGroups', "$TD_OperatorGroup_UNID");

       if (!defined($TD_OperatorGroup_UNID))
          {
          print "Error (create incident): No operator group UNID found for operator group $TD_OperatorGroup in config file\n";
          exit 2;
          }
       
       $request = $request . "\"operatorGroup\": {  \"id\": \"" . $TD_OperatorGroup_UNID . "\" }";
       }

    $request = $request . " }";

    $TD_Rest_Client->POST($CreateIncident_URL, $request, $HTTP_headers); 

    $HTTP_Ret_Code = $TD_Rest_Client->responseCode();

    if ( $HTTP_Ret_Code == 201 )
       {
       $result = $TD_Rest_Client->responseContent();
       $result =~ s/,\"request.*$//;
       $result =~ s/^\{//;
       @result = split(/,/, $result);
       
       $incident_UNID = $result[0];
       $incident_UNID =~ s/\"//g;
       $incident_UNID =~ s/^.*://;
       $incident_UNID =~ s/-//g;

       $incident_number = $result[2];
       $incident_number =~ s/\"//g;
       $incident_number =~ s/^.*://;
       }

    if ( $HTTP_Ret_Code == 400 )
       {
       print "Error (create incident): Bad request. Error can be:\n";
       print "       The incident id is invalid\n";
       print "       The request contains a field that does not exist\n";
       print "       The request contains a value for a field where the format is wrong. For example, \"true\" mistyped, or the UUID in the wrong format\n";
       print "       The request contains a value for a string field which is too long. For example, brief description can only be 80 characters long\n";
       print "       The request contains an operator which does not belong to the given operator group\n";
       print "       The request contains a subcategory which does not belong to the given category\n";
       print "       The request contains a supplier which is not applicable for the status of the incident\n";
       print "       The request contains an invalid major call\n";
       print "       The person tries to give feedback on an open incident\n";
       shit_happens();
       exit 0;
       }

    if ( $HTTP_Ret_Code == 401 )
       {
       print "Error (create incident): Unaauthorized - no valid authorization token provided.\n";
       shit_happens();
       exit 0;
       }

    if ( $HTTP_Ret_Code == 403 )
       {
       print "Error (create incident): Access forbidden.\n";
       shit_happens();
       exit 0;
       }

    if ( $HTTP_Ret_Code == 404 )
       {
       print "Error (create incident): The request contains a field with an id value which is not existing in the database.\n";
       shit_happens();
       exit 0;
       }

    if ( $HTTP_Ret_Code == 500 )
       {
       print "Error (create incident): Internal server error\n";
       shit_happens();
       exit 0;
       }
    return ( "$incident_UNID" , "$incident_number" );
    }


sub modify_incident()
    {

    my $to_be_closed=$_[0];
    
    my $result = "";
    my @result;
    my $request = "{ ";
    
    # Unfortunately the value of the status has been changed
    # for the API from a number to a string. To avoid rewriting 
    # all code handling this we leave it unchanged in the rest of 
    # the code 
    
    my $TD_status_api;
    
    my $ModifyIncident_URL = $TD_URL . "/tas/api/incidents/number/$TD_incident_number";
    
    $HTTP_headers = {
                     Authorization => 'TOKEN id="'. $TD_Auth_Token . '"',
                     Accept => 'application/json', 
                    };

    if (!$TD_server)
       {
       print "Error (modify incident): No hostname given.\n";
       exit 2;
       }
		
    if (!defined($nag_service))
       {
       $TD_message="$TD_Timestamp  $TD_caller:  Host $nag_host - has recovered. Status $nag_state. - Message from Nagios: $nag_message";
       $request = $request . "\"action\": \"" . $TD_message . "\"";
       }
    else
       {
       $TD_message="$TD_Timestamp  $TD_caller:  Host $nag_host Service $nag_service - has recovered. Status: $nag_state. - Message from Nagios: $nag_message";
       $request = $request . "\"action\": \"" . $TD_message . "\"";
       }

    if ($TD_processing_status)
       {
       $request = $request . ", \"processingStatus\" : { \"id\" : \"" . $TD_processing_status_UNID . "\" }";
       }

    if ($TD_complete_close =~ m/closed/i )
       {
       $request = $request . ", \"closed\" : \"true\"";
       }

    if ($TD_complete_close =~ m/completed/i )
       {
       $request = $request . ", \"completed\" : \"true\"";
       }

    $request = $request . " }";

    $TD_Rest_Client->PUT($ModifyIncident_URL, $request, $HTTP_headers); 

    $HTTP_Ret_Code = $TD_Rest_Client->responseCode();

    if ( $HTTP_Ret_Code == 400 )
       {
       print "Error (modify incident): Bad request. Error can be:\n";
       print " The incident id is invalid\n";
       print " The request contains a field that does not exist\n";
       print " The request contains a value for a field where the format is wrong. For example, \"true\" mistyped, or the UUID in the wrong format\n";
       print " The request contains a value for a string field which is too long. For example, brief description can only be 80 characters long\n";
       print " The request contains an operator which does not belong to the given operator group\n";
       print " The request contains a subcategory which does not belong to the given category\n";
       print " The request contains a supplier which is not applicable for the status of the incident\n";
       print " The request contains an invalid major call\n";
       print " The person tries to give feedback on an open incident\n";
       shit_happens();
       exit 0;
       }

    if ( $HTTP_Ret_Code == 401 )
       {
       print "Error: Unaauthorized - no valid authorization token provided.\n";
       shit_happens();
       exit 0;
       }

    if ( $HTTP_Ret_Code == 403 )
       {
       print "Error (modify incident) (modify incident): Access forbidden.\n";
       shit_happens();
       exit 0;
       }

    if ( $HTTP_Ret_Code == 404 )
       {
       print "Error (modify incident): The request contains a field with an id value which is not existing in the database.\n";
       shit_happens();
       exit 0;
       }

    if ( $HTTP_Ret_Code == 500 )
       {
       print "Error (modify incident): Internal server error\n";
       shit_happens();
       exit 0;
       }
    }

# Here we acknowledge the problem in Nagios in case there was no error

sub set_acknowledge()
    {
    my $nag_ack_msg="";
    
    open(NAG_CMD, ">> $nag_pipe");
    
    if (!$nag_service)
       {
       $nag_ack_msg="[$timestamp] ACKNOWLEDGE_HOST_PROBLEM;$nag_host;1;1;1;$nag_contact;";
       $nag_ack_msg=$nag_ack_msg."An incident in TOPdesk was opened with id: ";
       $nag_ack_msg=$nag_ack_msg."<A HREF=\'$TD_URL/tas/secure/contained/incident?unid=$TD_incident_number_UNID\' target=\"_blank\">$TD_incident_number</A>\n";
          
       print NAG_CMD "$nag_ack_msg";

       }
    else
       {

       $nag_ack_msg="[$timestamp] ACKNOWLEDGE_SVC_PROBLEM;$nag_host;$nag_service;1;1;1;$nag_contact;";
       $nag_ack_msg=$nag_ack_msg."An incident in TOPdesk was opened with id: ";
       $nag_ack_msg=$nag_ack_msg."<A HREF=\'$TD_URL/tas/secure/contained/incident?unid=$TD_incident_number_UNID\' target=\"_blank\">$TD_incident_number</A>\n";
       
       print NAG_CMD "$nag_ack_msg";

       }

    close(NAG_CMD);
    }


# Here we add only a comment or the problem in Nagios in case we have trouble opening an incident in topdesk

sub set_comment()
    {

    my $nag_comment_msg="";
    
    open(NAG_CMD, ">> $nag_pipe");
    
    if (!$nag_service)
       {
       if ($HTTP_Ret_Code)
          {
          $nag_comment_msg="[$timestamp] ADD_HOST_COMMENT;$nag_host;1;$nag_contact;";
          $nag_comment_msg=$nag_comment_msg."An incident in TOPdesk could not be opened. HTTP status code: $HTTP_Ret_Code";
          print NAG_CMD "$nag_comment_msg";
          }
       else
          {
          $nag_comment_msg="[$timestamp] ADD_HOST_COMMENT;$nag_host;1;$nag_contact;";
          $nag_comment_msg=$nag_comment_msg."An incident in TOPdesk could not be opened. Maybe authentication wrong/disabled, server not running or protocol/port wrong.";
          print NAG_CMD "$nag_comment_msg";
          }
       }
    else
       {
       if ($HTTP_Ret_Code)
          {
          $nag_comment_msg="[$timestamp] ADD_SVC_COMMENT;$nag_host;$nag_service;1;$nag_contact;";
          $nag_comment_msg=$nag_comment_msg."An incident in TOPdesk could not be opened.  HTTP status code: $HTTP_Ret_Code";
          print NAG_CMD "$nag_comment_msg";
          }
       else
          {
          $nag_comment_msg="[$timestamp] ADD_SVC_COMMENT;$nag_host;$nag_service;1;$nag_contact;";
          $nag_comment_msg=$nag_comment_msg."An incident in TOPdesk could not be opened. Maybe authentication wrong/disabled, server not running or protocol/port wrong.";
          print NAG_CMD "$nag_comment_msg";
          }
       }

    close(NAG_CMD);
    }

# Here we store a temporary file containing the UNID

sub store_incident_id()
    {
    my $store_tmpfile=create_tmpfile_name();
   
    open(TMP_INCIDENTID, "> $store_tmpfile");
    
    print TMP_INCIDENTID "$TD_incident_number\n";

    close(TMP_INCIDENTID);
    }

sub get_incident_id_tmp_file()
    {
    my $get_tmpfile=create_tmpfile_name();
    my $content;
   
    if (-e $get_tmpfile)
       {
       open(TMP_INCIDENTID, "< $get_tmpfile");

       while (<TMP_INCIDENTID>)
             {
             $content="$_";
             }

       close(TMP_INCIDENTID);
       unlink ($get_tmpfile);
       }
    else
       {
       $content="NOF";
       }
    return $content;
    }


sub create_tmpfile_name()
    {
    my $tmpfile_service="";
    my $tmpfile_name="";
    
    # We construct the filename using TD_ as a prefix to make it easier to find the file in the temp directory.
    
    $tmpfile_name = $tmp_dir."/TD_".$nag_host;

    # If it is a a service problem we filter every whitspace characters out of the service description
    # In case of a host problem we have nothing to do
    
    if ($nag_service)
       {
       $tmpfile_service=$nag_service;
       $tmpfile_service =~ s/\s//isog;

       $tmpfile_name = $tmpfile_name."_".$tmpfile_service;
       }
    
    return $tmpfile_name;
    
    }


sub ping()
    {
    my $ping = Net::Ping->new("$ping_prot",20,15);
    
    if ( $ping->ping($_[0],20))
       {
       $ping="Alive";
       }
    else
       {
       $ping="Dead";
       }
    
    return $ping;
    
    }


sub shit_happens()
    {

    if ($nag_contact_email)
       {
       
       my $Type_of_call;
       
       open(MAIL, "|$mailer");
       
       # Mail Header
       print MAIL "To: $nag_contact_email\n";
       print MAIL "Subject: Alert from Nagios! $TD_URL not accessible. Cannot add incident!\n\n";

       $nag_contact_email =~ s/ /,/isog;
       
       if ( $HTTP_Ret_Code == 400 )
          {
          print MAIL "Error: HTTP return code $HTTP_Ret_Code. Bad request. Error can be:\n";
          print MAIL "       The incident id is invalid\n";
          print MAIL "       The request contains a field that does not exist\n";
          print MAIL "       The request contains a value for a field where the format is wrong. For example, \"true\" mistyped, or the UUID in the wrong format\n";
          print MAIL "       The request contains a value for a string field which is too long. For example, brief description can only be 80 characters long\n";
          print MAIL "       The request contains an operator which does not belong to the given operator group\n";
          print MAIL "       The request contains a subcategory which does not belong to the given category\n";
          print MAIL "       The request contains a supplier which is not applicable for the status of the incident\n";
          print MAIL "       The request contains an invalid major call\n";
          print MAIL "       The person tries to give feedback on an open incident\n";
          print MAIL "\n";
          }
   
       if ( $HTTP_Ret_Code == 401 )
          {
          print MAIL "Error: HTTP return code $HTTP_Ret_Code. Invalid login credentials\n";
          print MAIL "\n";
          }
   
       if ( $HTTP_Ret_Code == 403 )
          {
          print MAIL "Error: HTTP return code $HTTP_Ret_Code. Access forbidden.\n";
          print MAIL "\n";
          }
   
       if ( $HTTP_Ret_Code == 404 )
          {
          print MAIL "Error: HTTP return code $HTTP_Ret_Code. The request contains a field with an id value which is not existing in the database.\n";
          print MAIL "\n";
          }
   
       if ( $HTTP_Ret_Code == 500 )
          {
          print MAIL "Error: HTTP return code $HTTP_Ret_Code. Internal server error\n";
          print MAIL "\n";
          }
   
       if ( $TD_status == 1 )
          {
          $Type_of_call = "1st";
          }

       if ( $TD_status == 2 )
          {
          $Type_of_call = "2nd";
          }

       # Mail Body
       print MAIL "Alert from Nagios! $TD_URL not accessible. Cannot add incident!\n";
       print MAIL "\n";
       print MAIL "$OptMailMsg\n";
       print MAIL "\n";
       print MAIL "Please add incident by hand when Topdesk is back to work:\n\n";
       print MAIL "#########################################################\n";
       print MAIL "# Instructions for registration in TOPdesk:\n";
       print MAIL "# =========================================\n";
       print MAIL "#\n";
       print MAIL "# Caller......: $TD_caller\n";
       print MAIL "#\n";
       print MAIL "# Category....: $TD_category\n";
       print MAIL "# Subcategory.: $TD_subcategory\n";
       print MAIL "# Type of call: $Type_of_call line call\n";
       print MAIL "# Duration....: $TD_severity\n";
       print MAIL "#########################################################\n\n";
       print MAIL "Error message from Nagios:\n";
       print MAIL "$TD_message\n";
 
       if ($HTTP_Ret_Code)
          {
          print MAIL "\nIt seems to be a problem with the Topdesk application:\n";
          print MAIL "HTTP status code: $HTTP_Ret_Code\n";
          }
    
       close(MAIL);
       }
    }


sub print_usage()
    {
    print "\nUsage: $ProgName -U|--url <TOPdesk base URL> ";
    print "[--config_dir=<Configuration file directoy> ";
    print "-H|--host <host> ";
    print "-S|--service <service> ";
    print "-N|--notificationtype <Nagios notificationtype> ";
    print "[-b|--briefdescription <Brief Description>] ";
    print "-M|--message <message> ";
    print "-C|--category <category> ";
    print "-c|--subcategory <subcategory> ";
    print "[-k|--caller <Caller>] ";
    print "[-e|--entry <Entry>] ";
    print "-s|--state <Nagios state> ";
    print "[-l|--line <1=1stline call, 2=2ndline call>] ";
    print "[--linemap=<\"s1=l1 s2=l1 s3=l2\"> ";
    print "[--sevmapfirst]] ";
    print "[--processing-status] ";
    print "[-O|--operator <operator group>] ";
    print "[-t|--severity <\"CRITICAL=2 WARNING=3 ...\">] ";
    print "[-W|--wait <wait for retry> ";
    print "[-w|--retry <retry interval> ";
    print "[-m|--mail <email-address>]]] ";
    print "[--optmailmsg=<message>]";
    print "[--close]\n\n";
    print "or\n";
    print "\nUsage: $ProgName -h for help.\n\n";
    }


sub print_help()
    {
    print "Copyright (c) 2009 - 2018 Martin Fuerstenau\n";
    print_usage();
    print "   -U, --url                                          TOPdesk base URL like\n";
    print "                                                      https://calldesk.oce.net (mandatory)\n";
    print "\n";
    print "       --config_dir=<Configuration file directoy>     Configuration file directory. (Optional)\n";
    print "                                                      Default is:\n";
    print "                                                      /etc/nagios/plugin.conf.d/handle_TD_incident\n";
    print "\n";
    print "   -u, --user                                         Topdesk user to open a ticket if other\n";
    print "                                                      than the default user.\n";
    print "   -p, --password                                     Password for Topdeskif other than the default password.\n";
    print "   -H, --host                                         Host causing the incident from Nagios (mandatory)\n";
    print "   -S, --service                                      Service causing the incident from Nagios (mandatory if a service)\n";
    print "   -N, --notificationtype                             Notificationtype from from Nagios (mandatory)\n";
    print "   -b, --briefdescription                             It fills out the brief description field (optional)\n";
    print "   -M, --message                                      Message from Nagios (mandatory)\n";
    print "   -C, --category                                     Main category in TOPdesk (mandatory)\n";
    print "   -c, --subcategory                                  Subcategory in TOPdesk (mandatory)\n";
    print "   -k, --caller                                       Pass the caller to TOPdesk\n";
    print "                                                      If not passed the default caller from\n";
    print "                                                      the script will be used. (optional)\n";
    print "   -e, --entry                                        Entry field in TOPdesk (optional)\n";
    print "   -s, --state=state                                  State from Nagios (mandatory)\n";
    print "                                                      UP = Host up - used for closing\n";
    print "                                                      an incident\n";
    print "                                                      DOWN = Host down\n";
    print "                                                      Normally mapped to severity 1\n";
    print "                                                      UNREACHABLE = Host unreachable\n";
    print "                                                      Normally mapped to severity 3\n";
    print "                                                      OK = Service ok - used for closing\n";
    print "                                                      an incident\n";
    print "                                                      WARNING = Service Warning\n";
    print "                                                      Normally mapped to severity 2\n";
    print "                                                      CRITICAL = Service critical\n";
    print "                                                      Normally mapped to severity 1\n";
    print "                                                      UNKNOWN = Service unknown\n";
    print "                                                      Normally mapped to severity 3\n";
    print "   -l, --line                                         1 indicates a first line incident, 2 indicates\n";
    print "                                                      a second line incident. If the default will\n";
    print "                                                      take place. (optional).\n";
    print "       --linemap=\"s1=l1 s2=l1 s3=l2\"                Map severity to line (1st line, 2nd line etc.).(optional)\n";
    print "                                                      Severity mapping (see below) is interpreted first!!\n";
    print "       --sevmapfirst                                  Priority for linemapping . This is used in conjunction with\n";
    print "                                                      severity mapping and line mapping.If (for example) a CRITICAL\n";
    print "                                                      is mapped to sev2 instead of a sev1 a line mapping like \"s1=l1 s2=l1\"";
    print "                                                      is nonsense because you will never have a sev1. So under normal\n";
    print "                                                      conditions the the line mapping must be done before the severity\n";
    print "                                                      is mapped. (Optional)\n";
    print "   -O, --operator=<operatorgroup>                     Sets the operator group in the operator\n";
    print "\n";
    print "       --processing-status=\"text string\"            Contains the processing-status in case of a recovery.\n";
    print "                                                      See your Topdesk system at \"Processing\" for possible values.\n";
    print "\n";
    print "   -t, --severity=\"CRITICAL=2 WARNING=3 ...\"          Severity for Topdesk (1,2,3 or 4)(optional)\n";
    print "                                                      With this switch you can overrite\n";
    print "                                                      the default mapping. The alternative mapping\n";
    print "                                                      should be entered as a string in the form\n";
    print "                                                      \"CRITICAL=1 WARNING=3....\" etc.\n";
    print "                                                      Lowercase letters will be converted to uppercase ones\n";
    print "                                                      You have only to add mappings, which should be \n";
    print "                                                      different from standard mapping\n";
    print "                                                      Mapping should be handled over as a string so don't\n";
    print "                                                      omit the quotes\n";
    print "   -W, --wait=time in minutes                         Time in minutes for waiting if the Topdesk\n";
    print "                                                      server is not responding. -m must be set also.(optional)\n";
    print "   -w, --retry=time in seconds                        Time in seconds for retry interval. Must be used\n";
    print "                                                      in conjunction with -W. (optional)\n";
    print "   -m, --mail='email address'                         Email address for notification if the Topdesk server is not \n";
    print "                                                      responding. Must be used with -W and -w (optional)\n";
    print "                                                      If a ticket is not older than given timeframe it will be\n";
    print "                                                      closed or completed. The decision to complete or close a ticket\n";
    print "                                                      is based on the policy used on the given server and therfore it\n";
    print "                                                      depends on the server name.\n";
    print "       --optmailmsg='message'                         This opens the option to handle an optional mail message in case\n";
    print "                                                      Topdesk is not reachable. This can be text like \"Call 911\"\n";
    print "                                                      or something else.\n";
    print "       --ping='protocol'                              Protocol to ping the Topdesk server. icmp is default but need root\n";
    print "                                                      privileges. Allowed protocols are icmp,tcp and udp.\n";
    print "\n";
    print "       --close                                        Always complete or close an incident (optional). The behaviour will\n";
    print "                                                      be defined in the .cfg file in the [Close] section.\n";
    print "\n";
    print "   -h, --help                                         Short help message (mandatory)\n";
    print "\n";
    }

#--- End subroutines --------------------------------------------------------
