XMPP.pm 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. package Cpanel::iContact::Provider::XMPP;
  2. use strict;
  3. use warnings;
  4. use parent 'Cpanel::iContact::Provider';
  5. sub send {
  6. my ($self) = @_;
  7. my $args_hr = $self->{'args'};
  8. my @errs;
  9. my $subject_copy = $args_hr->{'subject'};
  10. my $body_copy = ${ $args_hr->{'text_body'} };
  11. require Encode;
  12. my $subject = Encode::decode_utf8( $subject_copy, $Encode::FB_QUIET );
  13. my $body = Encode::decode_utf8( $body_copy, $Encode::FB_QUIET );
  14. foreach my $destination ( @{ $args_hr->{'to'} } ) {
  15. local $@;
  16. eval {
  17. my $response;
  18. $self->_send(
  19. 'destination' => $destination,
  20. 'subject' => $subject,
  21. 'content' => $body
  22. );
  23. };
  24. push( @errs, $@ ) if $@;
  25. }
  26. if (@errs) {
  27. die "One or more notification attempts failed. Details below:\n"
  28. . join( "\n", @errs );
  29. }
  30. return 1;
  31. }
  32. sub _send {
  33. my ( $self, %args ) = @_;
  34. # Unfortunately you need this for Net::XMPP::Client to work.
  35. # Just requiring Net::XMPP::Client won't work.
  36. require Net::XMPP;
  37. my $user_name = substr( $self->{'contact'}{'XMPPUSERNAME'}, 0, index( $self->{'contact'}{'XMPPUSERNAME'}, '@' ));
  38. my $srvr_name = substr( $self->{'contact'}{'XMPPUSERNAME'}, index( $self->{'contact'}{'XMPPUSERNAME'}, '@' ) + 1 );
  39. # Safest assumption unless we the user gives a component name for override is to use base server name
  40. # Otherwise, expect a lot of "host-unknown" errors.
  41. my $cmpt_name = $self->{'contact'}{'XMPPCOMPONENTNAME'} || $srvr_name;
  42. # Set BINMODE to utf-8 on STDERR, as otherwise you'll get wide char in print warns in cPanel's Error log
  43. binmode STDERR, ':utf8';
  44. my $xmpp_conn = Net::XMPP::Client->new(
  45. # Uncomment the below for debugging info
  46. #'debuglevel' => 2,
  47. #'debugfile' => "/usr/local/cpanel/logs/iContact_XMPP_error_log",
  48. );
  49. require Mozilla::CA;
  50. # Will splash down without this
  51. my $cab_loc = Mozilla::CA::SSL_ca_file();
  52. # SIGALRM this to put a stop to folks who don't set SSL/TLS settings right (as Connect then foreverloops)
  53. my $status;
  54. {
  55. local $SIG{'ALRM'} = sub { die "Error: XMPP Connection failed: Timeout while attempting connection\n" };
  56. $self->{'_xmpp_alarm'} ||= 5; # For tests
  57. alarm $self->{'_xmpp_alarm'};
  58. $status = $xmpp_conn->Connect(
  59. 'hostname' => $srvr_name,
  60. 'componentname' => $cmpt_name,
  61. 'tls' => $self->{'contact'}{'XMPPUSETLS'},
  62. 'srv' => 1,
  63. 'ssl_ca_path' => $cab_loc,
  64. 'ssl_verify' => $self->{'contact'}{'XMPPVERIFYCERT'},
  65. );
  66. alarm 0;
  67. }
  68. if( !defined($status) ) {
  69. require Data::Dumper;
  70. die("Error: XMPP connection failed: " . Data::Dumper::Dumper($xmpp_conn->GetErrorCode()) );
  71. }
  72. my @result = $xmpp_conn->AuthSend(
  73. 'username' => $user_name,
  74. 'password' => $self->{'contact'}{'XMPPPASSWORD'},
  75. 'resource' => 'cPanel & WHM',
  76. );
  77. if( !@result || $result[0] ne "ok" ) {
  78. $xmpp_conn->Disconnect();
  79. die("Error: XMPP authentication failed: $result[1]" );
  80. }
  81. # TODO Error handling? There doesn't seem to be a good return from this sub.
  82. $xmpp_conn->MessageSend(
  83. 'to' => $args{'destination'},
  84. 'subject' => $args{'subject'},
  85. 'body' => $args{'content'},
  86. 'thread' => "cPNotifySpam",
  87. 'priority' => 10,
  88. );
  89. $xmpp_conn->Disconnect();
  90. return;
  91. }
  92. 1;