I'm currently trying to create and send articles via the SOAP interface with perl. I'm running into problems when submitting the article. Either 'text/plain' or 'text/html' body submitted via SOAP::Lite will be encoded (<>& etc), transmitted but not decoded on the OTRS server side. I'm having charset UTF-8 in the ArticleSend method as well as in OTRS itself and the database. When I'm submitting "PLAINTEXT<>&" it will be received and saved as "PLAINTEXT<>&" which is definitely a problem and I did not yet find a solution so I hope you'll be able to help.
I'm attaching the code (the client-library at least) here. Input comes from a MIME::Entity mail object which will be parsed for the necessary data for OTRS.
Code: Select all
#!/usr/bin/perl
package OTRS::Client;
use strict;
use warnings;
use SOAP::Lite;
use Data::Dumper;
use MIME::Entity;
use Encode;
use HTML::Entities;
use constant DEFAULT_SENDER_TYPE => 'system';
use constant DEFAULT_ARTICLE_TYPE => 'email-external';
use constant DEFAULT_LOCK_TYPE => 'unlock';
use constant DEFAULT_STATE => 'closed successful';
use constant DEFAULT_QUEUE => 'Raw';
use constant DEFAULT_OWNER_ID => 1;
use constant DEFAULT_USER_ID => 1;
use constant DEFAULT_PRIORITY => "3 normal";
my $RPC;
sub new {
my $class = shift;
my %data = @_;
my $self = {
_proxy => $data{proxy},
_uri => $data{uri},
_username => $data{username},
_password => $data{password},
};
print "Class: ".$class."\n";
print "Proxy: ".$self->{_proxy}."\n";
print "URI: ".$self->{_uri}."\n";
print "Username: ".$self->{_username}."\n";
print "Password: ".$self->{_password}."\n";
bless $self, $class;
# Create OTRS Soap Object
$RPC = new SOAP::Lite( encoding => 'utf-8', proxy => $self->{_proxy}, uri => $self->{_uri} );
return $self;
}
sub sendMail {
# Expects 1 Paramenter: MIME Entity
if (my ( $self, $mail ) = @_) {
# Get the mail head
my $head = $mail->head;
my %HEADER;
# Gather HEAD-Fields needed for OTRS
$HEADER{'From'} = $head->get('From');
$HEADER{'To'} = $head->get('To');
$HEADER{'Subject'} = $head->get('Subject');
$HEADER{'Content-Type'} = $head->get('Content-Type');
$HEADER{'Cc'} = $head->get('Cc')
if ($head->get('Cc'));
$HEADER{'ReplyTo'} = $head->get('Reply-To')
if ($head->get('Reply-To'));
# Check for OTRS X- Attributes
# ----------------------------
# X-OTRS-Type default
# X-OTRS-Service -
# X-OTRS-SLA -
# X-OTRS-ArticleKey(1|2|3)
# X-OTRS-ArticleValue(1|2|3)
# X-OTRS-TicketKey(1|2|...|8)
# X-OTRS-TicketValue(1|2|...|8)
# X-OTRS-Loop True (Default: true)
my %OTRS_TICKET_FLAGS;
my %OTRS_ARTICLE_FLAGS;
# X-OTRS-Priority 1 very low, 2 low, 3 normal, 4 high, 5 very high
$OTRS_TICKET_FLAGS{'Priority'} = ($head->get('X-OTRS-Priority')) ? $head->get('X-OTRS-Priority') : DEFAULT_PRIORITY;
# X-OTRS-Queue Queue-Name
$OTRS_TICKET_FLAGS{'Queue'} = ($head->get('X-OTRS-Queue')) ? $head->get('X-OTRS-Queue') : DEFAULT_QUEUE;
# X-OTRS-Lock lock,unlock
$OTRS_TICKET_FLAGS{'Lock'} = ($head->get('X-OTRS-Lock')) ? $head->get('X-OTRS-Lock') : DEFAULT_LOCK_TYPE;
# X-OTRS-State new, open, closed successful, closed unsuccessful, ...
$OTRS_TICKET_FLAGS{'State'} = ($head->get('X-OTRS-State')) ? $head->get('X-OTRS-State') : DEFAULT_STATE;
# X-OTRS-State-PendingTime 2010-11-20 00:00:00
$OTRS_TICKET_FLAGS{'State-PendingTime'} = $head->get('X-OTRS-State-PendingTime')
if ($head->get('X-OTRS-State-PendingTime'));
# X-OTRS-CustomerUser CustomerUser
$OTRS_TICKET_FLAGS{'CustomerUser'} = $head->get('X-OTRS-CustomerUser')
if ($head->get('X-OTRS-CustomerUser'));
# X-OTRS-CustomerNo CustomerNo
$OTRS_TICKET_FLAGS{'CustomerNo'} = $head->get('X-OTRS-CustomerNo')
if ($head->get('X-OTRS-CustomerNo'));
# X-OTRS-SenderType agent, system, customer
$OTRS_ARTICLE_FLAGS{'SenderType'} = ($head->get('X-OTRS-SenderType')) ? $head->get('X-OTRS-SenderType') : DEFAULT_SENDER_TYPE;
# X-OTRS-ArticleType email-external, email-internal, email-notification-ext, email-notification-int, phone, fax, sms, webrequest, note-internal, note-external, note-report
$OTRS_ARTICLE_FLAGS{'ArticleType'} = ($head->get('X-OTRS-ArticleType')) ? $head->get('X-OTRS-ArticleType') : DEFAULT_ARTICLE_TYPE;
# Create Ticketnumber
my $SOM = $RPC->Dispatch( $self->{_username}, $self->{_password}, 'TicketObject', 'TicketCreateNumber' );
die $SOM->fault()->{faultstring} if $SOM->fault();
my $TicketNumber = $SOM->result();
if ($TicketNumber) {
# Create Ticket
my %TicketData = (
TN => $TicketNumber,
Title => $HEADER{'Subject'},
OwnerID => DEFAULT_OWNER_ID,
UserID => DEFAULT_USER_ID
);
%TicketData = (%TicketData,%OTRS_TICKET_FLAGS);
$SOM = $RPC->Dispatch( $self->{_username}, $self->{_password}, 'TicketObject', 'TicketCreate', %TicketData => 1 );
die $SOM->fault()->{faultstring} if $SOM->fault();
my $TicketID = $SOM->result();
# Ticket Created successfully
if ($TicketID) {
# Get Mail Body
# my $body = $mail->body;
my $body;
my $attachment;
my @attachments = ();
my $content_mime_type;
if ($mail->parts > 0) {
for (my $i=0;$i<$mail->parts;$i++) {
my $subEntity = $mail->parts($i);
print ">> MIME: ", $subEntity->mime_type," \n";
my $mime_type = $subEntity->mime_type;
#if ($mime_type eq 'text/plain') {
# if (my $io = $subEntity->open("r")) {
# while (defined($_=$io->getline)) {
# #print $_;
# #$body = $body.$_;
# $body = join "", @{$subEntity->body};
# next;
# }
# $io->close;
# }
# $attachment = {
# Content => $subEntity->bodyhandle->as_string,
# ContentType => $mime_type,
# MimeType => $mime_type
# };
# push (@attachments, $attachment);
#}
if ($mime_type eq 'text/html' || $mime_type eq 'text/plain') {
my $plainbody = $subEntity->stringify_body;
$body = $body.$plainbody;
$content_mime_type = $mime_type;
print Dumper($body);
}
else {
# It's any form of attachment
print "Filename: ".$subEntity->head->mime_attr('content-disposition.filename');
$attachment = {
Content => $subEntity->bodyhandle->as_string,
ContentType => $mime_type,
Filename => $subEntity->head->mime_attr('content-disposition.filename')
};
push (@attachments, $attachment);
}
}
}
else {
my $content_mime_type = $mail->mime_type;
$body = join "", @{$mail->body};
}
print Dumper($body);
print "MIME TYPE BEFORE ARRAY: ".$content_mime_type;
my %ArticleData = (
TicketID => $TicketID,
From => $HEADER{'From'},
To => $HEADER{'To'},
Cc => $HEADER{'Cc'},
ReplyTo => $HEADER{'ReplyTo'},
Subject => $HEADER{'Subject'},
#ContentType => $content_mime_type,
MimeType => $content_mime_type,
#MimeType => $HEADER{'Content-Type'},
UserID => DEFAULT_USER_ID,
Body => $body,
Charset => 'utf-8',
HistoryType => 'EmailCustomer',
HistoryComment => 'Created by OTRS::Client Module',
NoAgentNotify => 0,
Loop => 0,
Attachment => \@attachments,
);
# Merge Arg Arrays
%ArticleData = (%ArticleData,%OTRS_ARTICLE_FLAGS);
$SOM = $RPC->Dispatch($self->{_username}, $self->{_password}, 'TicketObject', 'ArticleSend', %ArticleData => 1 );
die $SOM->fault()->{faultstring} if $SOM->fault();
my $ArticleID = $SOM->result();
print "NOTICE: ArticleID is $ArticleID\n";
}
}
return 1;
}
die;
}
1;
Code: Select all
my $client = new OTRS::Client(
proxy => "http://OTRSURL/otrs/rpc.pl",
uri => "http://localhost/Core",
username => "USER",
password => "PASS"
);
my $content = '<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html"/></head><body><h1><Hallo Welt</h1><p>TEST</p></body></html>';
my $content_plain = "PLAIN PLAIN PLAIN PLAIN<>&";
my $mail = MIME::Entity->build(
Type =>"multipart/alternative",
From => "test\@example.net",
To => "test1\@example.net",
Subject => "OTRS Perl Bridge TESTMAIL"
);
# $mail->attach(Path => "/usr/local/bin/pic1.jpg",
# Type => "image/jpeg",
# Encoding => "base64");
# $mail->attach(Path => "/usr/local/bin/pic2.gif",
# Type => "image/gif",
# Encoding => "base64");
$mail->attach( Data=>$content,
Type=>"text/html");
#$mail->attach( Data=>$content_plain,
# Type=>"text/plain");
$client->sendMail($mail);
