[horde] [whups]: whups-mail-filter assign to ticket type in queue

Carsten horde-groupware at familie-lahme.de
Wed Mar 14 22:41:22 UTC 2018



Am 14.03.2018 um 14:22 schrieb Carsten:
> Hi all,
>
> I wonder, if I understand the schematic of whups ticket system 
> correct, because I am struggling with the implementation.
>
> I understand, that each QUEUE represents a project, where a project 
> might be an asset (like a car or an house) or a workflow (compared to 
> plan a holiday tour).
>
> I see, that one QUEUE might have multiple types, as compared to a car, 
> that might have different kind of handlings, like a planned 
> maintenance or a unscheduled repair. More IT-Like: a change or an 
> incident.
>
> A vacation planning project might have different types of tasks, like 
> booking hotels or flights, buying special stuff like backpacks or tent 
> or just a new shaver.
>
> If I would like to feed this matrix, it would be great to have an 
> option, to pipe a message direct to the correct type.
>
> Like sending a new available fixpack for software to the QUEUE 
> "InternalIT" with TYPE "change" or the message of an unavailable 
> website to the type "incident".
>
> And for QUEUE "Holiday planning" it could be good to find the tent on 
> the "tobuy" "TYPE" list, but not the plane for the flight, which would 
> be good to have on type "tobook".
>
> This leads to the question, if it is possible to give "TYPE" with a 
> mail piped to "whups-mail-filter".
>
> What would be needed to implement it in the script. I am not familiar 
> with the API of whups. Is there any documentation about the functions 
> and workflows?
>
> If available, I would try by myself and post the result, if working as 
> some kind of "pull" request ;-)
>
> br
>
> Carsten
>

Hey, yes, Carsten, would be great to have somebody doing such coding.....
Well, what a storm for DEV-requests....
na.. just kidding ;-)

ok,
I have digged into the PHP code and I think, I got a solution.
What my change does, is to add an argument to the command line 
"--type"|"-t" which can hold the NAME of the requested type.
Additionaly it scans the piped mail for a line like
"type: [put your type here]"

Mail Body rules out Command line!

Next it scans for possible types and replaces the name with the id.
This is parsed to the regular function, and the ticket is assigned to 
the queue with the requested type.
If no type matches or is given, it falls back to "default".

And here comes my modified whups-mail-filter. Have fun with it, and feel 
free to comment and/or correct possible mistakes. Neither I am a great 
programmer nor a DEV Coder for applications, so please use with caution 
only on a test or dev platform.
!!!!__DO NOT USE UNTESTED IN PRODUCTION PLATFORMS__!!!!

Find the changes in between hashed lines
---------------------------------------------------------------
-- whups-mail-filter version with ticket type option
-- BoF
---------------------------------------------------------------
#!/usr/bin/php
<?php


/**
  * This script accepts a MIME message on standard input or from a mail 
server
  * and creates a new ticket from its contents.
  */

function usage()
{
     $argv = Console_Getopt::readPHPArgv();
     $cmd = basename($argv[0]);
     echo <<<EOU
Usage: $cmd [options]

This script parses MIME messages and creates new tickets from their 
contents.
Single messages can be passed to the script on standard input. If the --mail
parameters are used, all messages from a mail server folder are processed
instead.

Options:
     -h, --help           Give this help.
     -a, --default-auth   A default user to set as the ticket requester, 
if the
                          requester cannot be determined from the message.
     -q, --queue-name     The name of the queue where the ticket should be
                          added.
     -Q, --queue-id       The (numerical) ID of the queue where the ticket
                          should be added.
     -g, --guess-queue    Guess the correct queue name from the subject. 
If no
                          (substring) match is found, fall back to -Q or -q.
#################################################
##
## added the -t option
##
     -t, --type           type of Ticket
#################################################
     -k, --ticket         Add the message as a comment to this ticket 
instead
                          of creating a new ticket.
         --mail-host      The IMAP/POP3 server to get the messages from.
                          Defaults to "localhost".
         --mail-user      The user name for the mail server.
         --mail-pass      The password for the mail server.
         --mail-port      The mail server port. Defaults to "143".
         --mail-protocol  The mail server protocol. Defaults to 
"imap/notls".
         --mail-folder    The folder on the mail server. Defaults to 
"INBOX".

IDs are preferred over names because they are faster to process and avoid
character set ambiguities.

EOU;
}

function _dump($hash)
{
     $dump = '';
     if (empty($hash)) {
         return $dump;
     }
     $idlen = max(array_map('strlen', array_keys($hash)));
     foreach ($hash as $id => $value) {
         $dump .= sprintf("\n%${idlen}d: %s", $id, $value);
     }
     return $dump;
}

function _error()
{
     foreach (imap_errors() as $error) {
         $GLOBALS['cli']->message($error, 'cli.warning');
     }
}

if (file_exists(__DIR__ . '/../../whups/lib/Application.php')) {
     $baseDir = __DIR__ . '/../../';
} else {
     require_once 'PEAR/Config.php';
     $baseDir = PEAR_Config::singleton()
         ->get('horde_dir', null, 'pear.horde.org') . '/whups/';
}
require_once $baseDir . 'lib/Application.php';
Horde_Registry::appInit('whups', array('cli' => true));

// Set server name.
$conf['server']['name'] = $conf['mail']['server_name'];
$conf['server']['port'] = $conf['mail']['server_port'];

// Read command-line parameters.
$info = array();
$mail = array('host' => 'localhost',
               'pass' => '',
               'port' => 143,
               'protocol' => 'imap/notls',
               'folder' => 'INBOX');
$from_mail = false;

// @TODO: Horde_Argv
##################################################
##
## added the 't' to the Argv
##
$options = Console_Getopt::getopt(Console_Getopt::readPHPArgv(),
                                   'ha:q:Q:gk:t:',
                                   array('help',
                                         'default-auth=',
                                         'queue-name=', 'queue-id=',
                                         'guess-queue',
                                         'ticket=',
                                         'mail-host=', 'mail-user=',
                                         'mail-pass=', 'mail-port=',
                                         'mail-protocol=', 'mail-folder='));
#####################################################
if (is_a($options, 'PEAR_Error')) {
     usage();
     $cli->fatal($options->getMessage());
}

// Convert options into a hash. This is possible because all options are 
only
// allowed once.
$opts_hash = array();
list($opts, $args) = $options;
foreach ($opts as $opt) {
     list($optName, $optValue) = $opt;
     switch ($optName) {
         case 'h': $optName = '--help'; break;
         case 'a': $optName = '--default-auth'; break;
         case 'k': $optName = '--ticket'; break;
         case 't': $optName = '--type'; break;
         case 'q': $optName = '--queue-name'; break;
         case 'Q': $optName = '--queue-id'; break;
         case 'g': $optName = '--guess-queue'; break;
     }
     $opts_hash[$optName] = is_null($optValue) ? true : $optValue;
}

// Process options in this order because some depend on others.
if (isset($opts_hash['--help'])) {
     usage();
     exit;
}
if (isset($opts_hash['--default-auth'])) {
     $info['default_auth'] = $opts_hash['--default-auth'];
     $registry->setAuth($info['default_auth'], array());
}
if (isset($opts_hash['--ticket'])) {
     $info['ticket'] = (int)$opts_hash['--ticket'];
}
if (isset($opts_hash['--guess-queue'])) {
     $info['guess-queue'] = true;
}
if (isset($opts_hash['--queue-name'])) {
     $queues = $whups_driver->getQueues();
     foreach ($queues as $queueId => $queueName) {
         if (strcasecmp($queueName, $opts_hash['--queue-name']) == 0) {
             $info['queue'] = $queueId;
             break;
         }
     }
}
if (isset($opts_hash['--queue-id'])) {
     $queues = $whups_driver->getQueues();
     foreach ($queues as $queueId => $queueName) {
         if (strcasecmp($queueId, $opts_hash['--queue-id']) == 0) {
             $info['queue'] = $queueId;
             break;
         }
     }
}
##############################################
####### Ticket Type test
##
# we will need to parse the stdin and so we will store it
# this impacts the later call of the function, because now the
# pipe is empty

$this_stdin=$cli->readStdin();

# now check, if we gave a type by command line argument
if (isset($opts_hash['--type'])) {
     $info['type'] = $opts_hash['--type'];
}

# if it is set in the mail, it overwrites the cli argument
preg_match("/(^type: )(.*)$/im",$this_stdin,$matchtype);
if ($matchtype[2] <> "") {
     $info['type'] = strtolower($matchtype[2]);
}


# if we got a type, we need to resolve it to its ID
if (isset($info['type'])) {
     $types = $whups_driver->getTypes($info['queue']);
     foreach ($types as $typeId => $typeName) {
         if (strcasecmp($typeName, $info['type']) == 0) {
             $info['type'] = $typeId;
             break;
         }
     }
}
##
####################################################

foreach (array('host', 'user', 'pass', 'port', 'protocol', 'folder') as 
$opt) {
     if (isset($opts_hash['--mail-' . $opt])) {
         $mail[$opt] = $opts_hash['--mail-' . $opt];
     }
}

// Sanity check options.
if (empty($info['ticket'])) {
     if (empty($info['queue'])) {
         usage();
         $msg = _("--queue-name or --queue-id must specify a valid and 
public queue.");
         if (isset($queues)) {
             $msg .= ' ' . _("Available queues:") . _dump($queues);
         }
         $cli->fatal($msg);
     }
}

// Read and parse the message.
if (empty($mail['user'])) {
     try {
##########################################
##
## replaced the $cli -> readStdin() methode with the dummy variable
##
         Whups_Mail::processMail($this_stdin, $info);
##########################################
     } catch (Whups_Exception $e) {
         $cli->fatal($e);
     }
} else {
     $messages = array();
     $imap = imap_open(sprintf('{%s:%d/%s}%s',
                                $mail['host'],
                                $mail['port'],
                                $mail['protocol'],
                                $mail['folder']),
                        $mail['user'], $mail['pass']);
     if (!$imap) {
         $cli->fatal(_("Cannot authenticate at mail server:") . ' ' . 
implode('; ', imap_errors()));
     }
     _error();
     $mailbox = imap_search($imap, 'ALL', SE_UID);
     _error();
     if ($mailbox) {
         foreach ($mailbox as $uid) {
             $message = imap_fetchheader($imap, $uid, FT_UID)
                 . imap_body($imap, $uid, FT_UID);

             try {
                 Whups_Mail::processMail($message, $info);
                 imap_delete($imap, $uid, FT_UID);
             } catch (Whups_Exception $e) {
                 $cli->message(_("Error processing message:") . ' ' . 
$e->getMessage(), 'cli.error');
             }
         }
     }
     imap_expunge($imap);
     imap_close($imap);
}

exit(0);
-----------------------------------------------------------------------
-- EoF
-----------------------------------------------------------------------

And here is an examble, to test it:
-----------------------------------------------------------------------
-- Test Bash Script
-- BoF
-----------------------------------------------------------------------
#!/bin/bash
echo "From: [put your sending mail address here]
To: [put Your receiving whups mail here]
subject: [Queuename]: Testticket with type

type: [put your desired type here]

Hello World

"|/usr/bin/whups-mail-filter -g -Q 8 -t '[put your desired type here]';
-----------------------------------------------------------------------
-- EoF
-----------------------------------------------------------------------

Have fun
Carsten

TODO:
--cut out the "type: xxx" line after match found
--adapt on queue to be read from mail body not from subject alone


More information about the horde mailing list