├── Changes ├── INSTALL ├── MANIFEST ├── META.yml ├── Makefile.PL ├── README ├── examples ├── send-url.xml └── sendxmpp-raw-messages ├── sendxmpp └── sendxmpp2 /Changes: -------------------------------------------------------------------------------- 1 | 2014-09-13: 2 | - released version 1.24 3 | - new config format supported - key: value 4 | 2012-10-28: 5 | - released version 1.23 6 | - added options --no-tls-verify and --tls-ca-path, thanks to Alexander Weidinger 7 | 8 | 2012-10-20: 9 | - CVS repository of sendxmpp migrated to Git repository https://github.com/lhost/sendxmpp 10 | - Homepage URL changed to http://sendxmpp.hostname.sk 11 | 12 | 2008-10-21: 13 | - Added support for 'chat' message type. Implemented modified version of 14 | messsage-type-chat.patch from Marc Mims 15 | Supported message types are 'message', 'chat', 'headline'. 16 | Default message type is 'message'. 17 | 18 | 2008-08-25: 19 | - Fix: fixed parsing of account with specific connection host 20 | Thanks to Klaus Alexander Seistrup 21 | 22 | 2007-09-10: 23 | - Fix: config file permission check did not allow read only file (Andrej Mikus) 24 | - Fix: authentication to Google Talk server (Andrej Mikus) 25 | - Feature: added a -l/--headline option to sendxmpp, to allow to send 26 | a headline type message(Jerome Sautret ) 27 | 28 | 2007-03-25: 29 | - Fix: groupchat message doesn't has subject attribute. Thanks to Jakub Tucek 30 | 31 | 2006-10-17: 32 | - Added support for raw XML messages. Thanks to David Ammouial 33 | - Documentation enhancement. Thanks to David Ammouial 34 | 35 | 2006-10-04: 36 | - Fixed sending of UTF-8 messages: patch from Denis Shaposhnikov [2006-03-31] 37 | - Print error message on connect error. Patch from Jean-Baptiste Quenot [2006-07-17] 38 | - Added multiple recipient patch by Lubomir Host [2006-08-30] 39 | - Fixed bug with -message parameter. Thanks to Thomas Warnick [2005-09-06] 40 | - Homepage URL changed to http://sendxmpp.platon.sk 41 | 42 | 2006-09-25: maintainer change 43 | - New maintainer is Lubomir Host 44 | 45 | 2005-05-07: version 0.0.8 released. 46 | - add options to specify non-default ports 47 | - updated documentation 48 | 49 | 2005-05-02: version 0.0.7 released / version 0.0.7.1. 50 | - add --interactive mode to send from stdin line-by-line 51 | - fix for typo ==> 0.0.7.1 52 | - documentation updates 53 | 54 | 2004-12-07: version 0.0.6 released. 55 | - fix for installation paths 56 | 57 | 2004-12-01: version 0.0.5 released. 58 | - don't be too picky about passwords 59 | - verbose output 60 | - better error handling 61 | - improved documentation 62 | - use subject for chatroom 63 | 64 | 2004-11-21: version 0.0.4 released. 65 | - small fixes 66 | - packaging (after Gentoo request) 67 | - documentation (man) 68 | 69 | 2004-11-17: version 0.0.3 is released. New features are: 70 | - Support for authentication using SSL/TLS; 71 | - Support for sending messages to chatrooms; 72 | - Support for providing login information on the command line; 73 | - Improved error handling; 74 | - NOTE: the .sendxmpprc format has changed. 75 | 76 | 2004-11-01: version 0.0.2 released. Initial release 77 | 78 | 79 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | INSTALL 2 | ------- 3 | 4 | Installation of required packages 5 | ---------------------------------- 6 | 7 | On Debian: 8 | 9 | sudo apt-get install libconfig-yaml-perl libnet-xmpp-perl libanyevent-xmpp-perl 10 | 11 | Installation from Git repository: 12 | --------------------------------- 13 | 14 | cd /tmp 15 | git clone https://github.com/lhost/sendxmpp.git 16 | cd sendxmpp/ 17 | perl Makefile.PL 18 | make 19 | make install 20 | 21 | sendxmpp requires perl 5.x, Getopt::Long and Net::XMPP. 22 | 23 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | Makefile.PL 2 | MANIFEST 3 | sendxmpp 4 | Changes 5 | README 6 | INSTALL 7 | Changes 8 | META.yml Module meta-data (added by MakeMaker) 9 | -------------------------------------------------------------------------------- /META.yml: -------------------------------------------------------------------------------- 1 | name: sendxmpp 2 | version: 1.24 3 | version_from: sendxmpp 4 | installdirs: site 5 | requires: 6 | Getopt::Long: 2 7 | Net::XMPP: 1 8 | 9 | distribution_type: module 10 | generated_by: ExtUtils::MakeMaker version 6.17 11 | -------------------------------------------------------------------------------- /Makefile.PL: -------------------------------------------------------------------------------- 1 | # Time-stamp: <2004-11-21 00:27:48 (djcb)> 2 | 3 | use ExtUtils::MakeMaker; 4 | 5 | # do this so we default to install to /usr/local, unless 6 | # PREFIX is provided, ie.: 7 | # perl Makefile.pl PREFIX=/usr 8 | $ENV{'PREFIX'}='/usr/local/' unless ($ENV{'PREFIX'}); 9 | 10 | WriteMakefile ( 11 | NAME => 'sendxmpp', 12 | AUTHOR => 'Lubomir Host ', 13 | ABSTRACT => 'Script for sending XMPP messages (Jabber client)', 14 | PREREQ_PM => { 15 | 'Getopt::Long' => 2.00, 16 | 'Net::XMPP' => 1.0, 17 | 'AnyEvent::XMPP' => 0.55, 18 | }, 19 | VERSION_FROM => 'sendxmpp', 20 | EXE_FILES => ['sendxmpp', 'sendxmpp2'] 21 | ); 22 | 23 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | README 2 | ------ 3 | 4 | sendxmpp is a perl-script to send XMPP (jabber) messages, similar to 5 | what mail(1) does for mail. XMPP is an open, non-proprietary protocol 6 | for instant messaging. See www.jabber.org for more information. 7 | 8 | sendxmpp was written by me, Dirk-Jan C. Binnema, and is available under 9 | the term of the GNU General Public License v2. The hard work is done by 10 | Ryan Eatmon's Net::XMPP-modules, and you need have them installed for 11 | sendxmpp to work. Current maintainer is Lubomir Host 12 | 13 | Obviously, you also need a jabber account; they are freely available 14 | at jabber.org, but you can also install your own servers. 15 | 16 | sendxmpp is already in use for monitoring remote servers (servers can 17 | warn by sending xmpp-messages), and watching CVS commit messages 18 | (developers are all connected to a XMPP-chatroom to which messages are 19 | sent. 20 | 21 | I am interested in hearing about other uses. 22 | 23 | Homepage: http://sendxmpp.hostname.sk 24 | 25 | Lubomir Host 26 | 27 | -------------------------------------------------------------------------------- /examples/send-url.xml: -------------------------------------------------------------------------------- 1 | 2 | Check out the new sendxmpp website! 3 | 4 | http://sendxmpp.hostname.sk/ 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/sendxmpp-raw-messages: -------------------------------------------------------------------------------- 1 | # 2 | # RAW XMPP messages, which can be used with sendxmpp 3 | # 4 | # Thanks to David Ammouial 5 | # 6 | # cat examples/send-url.xml | sendxmpp --raw 7 | # 8 | 9 | # Sending an URL along with a message: 10 | 11 | Check out the new sendxmpp website! 12 | 13 | http://sendxmpp.hostname.sk/ 14 | 15 | 16 | 17 | # Adding an item to the roster 18 | 19 | 20 | 21 | 22 | 23 | 24 | # Sending a presence subscription request 25 | 26 | Please authorize me :) 27 | 28 | 29 | -------------------------------------------------------------------------------- /sendxmpp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | eval 'exec /usr/bin/perl -w -S $0 ${1+"$@"}' 4 | if 0; # not running under some shell 5 | 6 | # 7 | # script to send message using xmpp (aka jabber), 8 | # somewhat resembling mail(1) 9 | # 10 | # Author: Dirk-Jan C. Binnema 11 | # Maintainer: Lubomir Host 12 | # Copyright (c) 2004 - 2005 Dirk-Jan C. Binnema 13 | # Copyright (c) 2006 - 2014 Lubomir Host 14 | # 15 | # Homepage: http://sendxmpp.hostname.sk 16 | # 17 | # Released under the terms of the GNU General Public License v2 18 | # 19 | 20 | use Authen::SASL qw(Perl); # authentication broken if Authen::SASL::Cyrus module installed 21 | use Net::XMPP; 22 | use Net::Domain; 23 | use Getopt::Long; 24 | 25 | use strict; 26 | 27 | use open ':utf8'; 28 | use open ':std'; 29 | 30 | # subroutines decls 31 | sub xmpp_login($$$$$$$$$$$$$); 32 | sub xmpp_send ($$$$); 33 | sub xmpp_send_raw_xml($$); 34 | sub xmpp_send_message($$$$$$); 35 | sub xmpp_send_chatroom_message($$$$$); 36 | sub xmpp_logout($); 37 | sub xmpp_check_result; 38 | sub parse_cmdline(); 39 | sub error_exit; 40 | sub debug_print; 41 | sub read_config_file($); 42 | sub push_hash($$); 43 | sub terminate(); 44 | sub main(); 45 | 46 | my # MakeMaker 47 | $VERSION = 1.24; 48 | my $RESOURCE = 'sendxmpp'; 49 | my $VERBOSE = 0; 50 | my $DEBUG = 0; 51 | # http://tools.ietf.org/html/rfc3921#section-2 section 2.1.1 - Types of Message 52 | my @suppported_message_types = qw( chat error groupchat headline ); 53 | my $message_type = 'chat'; # default message type 54 | 55 | # start! 56 | &main; 57 | 58 | # 59 | # main: main routine 60 | # 61 | sub main () { # {{{ 62 | 63 | my $cmdline = parse_cmdline(); 64 | 65 | $| = 1; # no output buffering 66 | 67 | $DEBUG = 1 if ($$cmdline{'debug'}); 68 | $VERBOSE = 1 if ($$cmdline{'verbose'}); 69 | 70 | my $config = read_config_file ($$cmdline{'file'}) 71 | unless ($$cmdline{'sso'} || ($$cmdline{'username'} && $$cmdline{'password'})); 72 | 73 | # login to xmpp 74 | my $cnx = xmpp_login ( 75 | $$cmdline{'jserver'} || $$config{'jserver'}, 76 | $$cmdline{'port'} || $$config{'port'} || ($$cmdline{'ssl'} ? 5223 : 5222), 77 | $$cmdline{'username'} || $$config{'username'}, 78 | $$cmdline{'password'} || $$config{'password'}, 79 | $$cmdline{'component'}|| $$config{'component'}, 80 | $$cmdline{'resource'}, 81 | $$cmdline{'tls'} || $$config{'tls'} || 0, 82 | $$cmdline{'no-tls-verify'} || $$config{'no-tls-verify'}, 83 | $$cmdline{'tls-ca-path'} || $$config{'tls-ca-path'} || '', 84 | $$cmdline{'ssl'}, 85 | $$cmdline{'http'} || $$config{'http'} || 0, 86 | $$cmdline{'debug'}, 87 | $$cmdline{'sso'} 88 | ) or error_exit("cannot login: $!"); 89 | 90 | 91 | # read message from STDIN or from -m/--message parameter 92 | if (!$$cmdline{interactive}) { 93 | # the non-interactive case 94 | my $txt; 95 | my $message = $$cmdline{'message'}; 96 | if ($message) { 97 | open (MSG, "<$message") 98 | or error_exit ("cannot open message file '$message': $!"); 99 | while () { $txt .= $_ }; 100 | close(MSG); 101 | } 102 | else { 103 | $txt .= $_ while (); 104 | } 105 | 106 | xmpp_send ($cnx, $cmdline, $config, $txt); 107 | 108 | } 109 | else { 110 | # the interactive case, read stdin line by line 111 | 112 | # deal with TERM 113 | $main::CNX = $cnx; 114 | $SIG{INT}=\&terminate; 115 | 116 | # line by line... 117 | while () { 118 | chomp; 119 | xmpp_send ($cnx, $cmdline, $config, $_); 120 | } 121 | } 122 | 123 | xmpp_logout($cnx); 124 | exit 0; 125 | } # }}} 126 | 127 | # 128 | # read_config_file: read the configuration file 129 | # input: filename 130 | # output: hash with 'user', 'jserver' and 'password' keys 131 | # 132 | sub read_config_file ($) { # {{{ 133 | 134 | # check permissions 135 | my $cfg_file = shift; 136 | error_exit ("cannot read $cfg_file: $!") 137 | unless (-r $cfg_file); 138 | my $owner = (stat _ )[4]; 139 | error_exit ("you must own $cfg_file") 140 | unless ($owner == $>); 141 | my $mode = (stat _ )[2] & 07777; 142 | error_exit ("$cfg_file must not be accessible by others") 143 | if ($mode & 0077); 144 | 145 | open (CFG, "<$cfg_file") 146 | or error_exit("cannot open $cfg_file for reading: $!"); 147 | 148 | my %config; 149 | my $line = 0; 150 | while () { 151 | 152 | ++$line; 153 | 154 | next if (/^\s*$/); # ignore empty lines 155 | next if (/^\s*\#.*/); # ignore comment lines 156 | 157 | #s/\#.*$//; # ignore comments in lines 158 | 159 | if (/^([a-z-]+):\s*(.*)$/) { 160 | $config{$1} = $2; 161 | } 162 | # Hugo van der Kooij has account with '#' as username 163 | elsif (/([\.\w_#-]+)@([-\.\w:;]+)\s+(\S+)\s*(\S+)?$/) { 164 | %config = ( 165 | 'username' => $1, 166 | 'jserver' => $2, 167 | 'port' => 0, 168 | 'password' => $3, 169 | 'component' => $4, 170 | ); 171 | 172 | } 173 | else { 174 | close CFG; 175 | error_exit ("syntax error in line $line of $cfg_file"); 176 | } 177 | 178 | # account with weird port number 179 | if (defined($config{'jserver'}) and $config{'jserver'} =~ /(.*):(\d+)/) { 180 | $config{'jserver'} = $1; 181 | $config{'port'} = $2; 182 | } 183 | 184 | # account with specific connection host 185 | if (defined($config{'jserver'}) and $config{'jserver'} =~ /(.*);([-\.\w]+)/) { 186 | $config{'jserver'} = $2; 187 | $config{'username'} .= "\@$1" unless $config{'component'}; 188 | } 189 | } 190 | 191 | close CFG; 192 | 193 | error_exit ("no correct config found in $cfg_file") 194 | unless (scalar(%config)); 195 | 196 | if ($DEBUG || $VERBOSE) { 197 | while (my ($key, $val) = each %config) { 198 | debug_print ("config: '$key' => '$val'"); 199 | } 200 | } 201 | 202 | return \%config; 203 | } # }}} 204 | 205 | # 206 | # parse_cmdline: parse commandline options 207 | # output: hash with commandline options 208 | # 209 | sub parse_cmdline () { # {{{ 210 | 211 | usage() unless (scalar(@ARGV)); 212 | 213 | my ($subject, $file, $resource, $jserver, $port, $username, $password, $sso, $component, 214 | $message, $chatroom, $headline, $debug, $tls, $ssl, 215 | $no_tls_verify, $tls_ca_path, $http, 216 | $interactive, $help, $raw, $verbose 217 | ); 218 | $debug = 0; 219 | my $res = GetOptions ( 220 | 'subject|s=s' => \$subject, 221 | 'file|f=s' => \$file, 222 | 'resource|r=s' => \$resource, 223 | 'jserver|j=s' => \$jserver, 224 | 'component|o=s' => \$component, 225 | 'username|u=s' => \$username, 226 | 'password|p=s' => \$password, 227 | 'sso' => \$sso, 228 | 'message|m=s' => \$message, 229 | 'headline|l' => \$headline, 230 | 'message-type=s' => \$message_type, 231 | 'chatroom|c' => \$chatroom, 232 | 'tls|t' => \$tls, 233 | 'no-tls-verify|n' => \$no_tls_verify, 234 | 'tls-ca-path|a=s' => \$tls_ca_path, 235 | 'ssl|e' => \$ssl, 236 | 'http' => \$http, 237 | 'interactive|i' => \$interactive, 238 | 'help|usage|h' => \$help, 239 | 'debug|d:i' => sub { $debug = $_[1] ? $_[1] : $debug + 1 }, 240 | 'raw|w' => \$raw, 241 | 'verbose|v' => \$verbose 242 | ); 243 | 244 | usage () if ($help); 245 | 246 | my @rcpt = @ARGV; 247 | 248 | if (defined($raw) && scalar(@rcpt) > 0) { 249 | error_exit("You must give a recipient or --raw (but not both)"); 250 | } 251 | if ($raw && $subject) { 252 | error_exit("You cannot specify a subject in raw XML mode"); 253 | } 254 | if ($raw && $chatroom) { 255 | error_exit("The chatroom option is pointless in raw XML mode"); 256 | } 257 | 258 | if ($message && $interactive) { 259 | error_exit("Cannot have both -m (--message) and -i (--interactive)"); 260 | } 261 | 262 | if (scalar(grep { $message_type eq $_ } @suppported_message_types) == 0) { 263 | error_exit("Unsupported message type '$message_type'"); 264 | } 265 | 266 | if ($ssl && $tls) { 267 | error_exit("Connect securely wether using -e (--ssl) or -t (--tls)"); 268 | } 269 | 270 | if ($sso && $username) { 271 | error_exit("When using --sso, user should not be specified"); 272 | } 273 | 274 | if ($headline) { 275 | # --headline withouth --message-type 276 | if ($message_type eq 'message' or $message_type eq 'chat') { 277 | $message_type = 'headline' 278 | } 279 | else { 280 | error_exit("Options --headline and --message-type are mutually exclusive"); 281 | } 282 | } 283 | 284 | if ($jserver && $jserver =~ /(.*):(\d+)/) { 285 | $jserver = $1; 286 | $port = $2; 287 | } 288 | 289 | my %dict = ( 290 | 'subject' => ($subject or ''), 291 | 'message' => ($message or ''), 292 | 'resource' => ($resource or $RESOURCE), 293 | 'jserver' => ($jserver or ''), 294 | 'component' => ($component or ''), 295 | 'port' => ($port or 0), 296 | 'username' => ($username or ''), 297 | 'password' => ($password or ''), 298 | 'sso' => ($sso or 0), 299 | 'chatroom' => ($chatroom or 0), 300 | 'message-type' => $message_type, 301 | 'interactive' => ($interactive or 0), 302 | 'tls' => ($tls or 0), 303 | 'no-tls-verify' => ($no_tls_verify or 0), 304 | 'tls-ca-path' => ($tls_ca_path or ''), 305 | 'ssl' => ($ssl or 0), 306 | 'http' => ($http or 0), 307 | 'debug' => ($debug or 0), 308 | 'verbose' => ($verbose or 0), 309 | 'raw' => ($raw or 0), 310 | 'file' => ($file or ($ENV{'HOME'}.'/.sendxmpprc')), 311 | 'recipient' => \@rcpt 312 | ); 313 | 314 | if ($DEBUG || $VERBOSE) { 315 | while (my ($key, $val) = each %dict) { 316 | debug_print ("cmdline: '$key' => '$val'"); 317 | } 318 | } 319 | 320 | return \%dict; 321 | } # }}} 322 | 323 | # 324 | # xmpp_login: login to the xmpp (jabber) server 325 | # input: hostname, port, username, password, resource, tls, ssl, http, debug 326 | # output: an XMPP connection object 327 | # 328 | sub xmpp_login ($$$$$$$$$$$$$) { # {{{ 329 | 330 | my ($host, $port, $user, $pw, $comp, $res, $tls, $no_tls_verify, $tls_ca_path, $ssl, $http, $debug, $sso) = @_; 331 | my $cnx = new Net::XMPP::Client(debuglevel=>$debug); 332 | error_exit "could not create XMPP client object: $!" 333 | unless ($cnx); 334 | 335 | my $ssl_verify = 0x01; 336 | if ($no_tls_verify) { $ssl_verify = 0x00; } 337 | debug_print "ssl_verify: $ssl_verify"; 338 | 339 | debug_print "tls_ca_path: $tls_ca_path"; 340 | 341 | my @res; 342 | my $arghash = { 343 | hostname => $host, 344 | port => $port, 345 | tls => $tls, 346 | ssl_verify => $ssl_verify, 347 | ssl_ca_path => $tls_ca_path, 348 | ssl => $ssl, 349 | connectiontype => $http ? 'http' : 'tcpip', 350 | componentname => $comp, 351 | srv => 1, # enable SRV lookups 352 | }; 353 | 354 | if ($sso) { 355 | $user = join('@', scalar getpwuid($<), Net::Domain::hostdomain()); 356 | debug_print "using SSO user $user"; 357 | } 358 | 359 | # use the xmpp domain as the host and enable SRV lookups 360 | if (!$host) { 361 | if ($user =~ /([\.\w_#-]+)@(.*)/) { 362 | $arghash->{hostname} = $host = $2; 363 | $arghash->{componentname} = $2; 364 | $user = $1; 365 | $arghash->{srv} = 1; 366 | debug_print "enabling SRV lookups"; 367 | 368 | } else { 369 | error_exit "unable to determine a host to connect to (no cmdline, no config, no SRV possible)"; 370 | } 371 | 372 | } 373 | 374 | delete $arghash->{port} unless $port; 375 | if ($arghash->{port}) { 376 | @res = $cnx->Connect(%$arghash); 377 | error_exit ("Could not connect to '$host' on port $port: ".($cnx->GetErrorCode()||$@)) unless @res; 378 | } else { 379 | @res = $cnx->Connect(%$arghash); 380 | error_exit ("Could not connect to server '$host': ".($cnx->GetErrorCode()||$@)) unless @res; 381 | } 382 | 383 | xmpp_check_result("Connect", \@res, $cnx); 384 | 385 | if ($comp) { 386 | my $sid = $cnx->{SESSION}->{id}; 387 | $cnx->{STREAM}->{SIDS}->{$sid}->{hostname} = $comp 388 | } 389 | 390 | @res = $cnx->AuthSend(#'hostname' => $host, 391 | 'username' => $user, 392 | 'password' => $pw, 393 | 'resource' => $res); 394 | xmpp_check_result('AuthSend', \@res, $cnx); 395 | 396 | return $cnx; 397 | } # }}} 398 | 399 | # 400 | # xmmp_send: send the message, determine from cmdline 401 | # whether it's to individual or chatroom 402 | # 403 | sub xmpp_send ($$$$) { # {{{ 404 | 405 | my ($cnx, $cmdline, $config, $txt) = @_; 406 | 407 | unless ($$cmdline{'chatroom'}) { 408 | unless ($$cmdline{'raw'}) { 409 | map { 410 | xmpp_send_message ($cnx, 411 | $_, #$$cmdline{'recipient'}, 412 | $$cmdline{'component'} || $$config{'component'}, 413 | $$cmdline{'subject'}, 414 | $$cmdline{'message-type'}, 415 | $txt) 416 | } @{$$cmdline{'recipient'}}; 417 | } 418 | else { 419 | xmpp_send_raw_xml ($cnx, $txt); 420 | } 421 | } 422 | else { 423 | map { 424 | xmpp_send_chatroom_message ($cnx, 425 | $$cmdline{'resource'}, 426 | $$cmdline{'subject'}, 427 | $_, # $$cmdline{'recipient'}, 428 | $txt) 429 | } @{$$cmdline{'recipient'}}; 430 | } 431 | } # }}} 432 | 433 | # 434 | # xmpp_send_raw_xml: send a raw XML packet 435 | # input: connection, packet 436 | # 437 | sub xmpp_send_raw_xml ($$) { # {{{ 438 | 439 | my ($cnx, $packet) = @_; 440 | 441 | # for some reason, Send does not return anything 442 | $cnx->Send($packet); 443 | xmpp_check_result('Send', 0, $cnx); 444 | } # }}} 445 | 446 | # 447 | # xmpp_send_message: send a message to some xmpp user 448 | # input: connection, recipient, subject, msg 449 | # 450 | sub xmpp_send_message ($$$$$$) { # {{{ 451 | 452 | my ($cnx, $rcpt, $comp, $subject, $message_type, $msg) = @_; 453 | 454 | # for some reason, MessageSend does not return anything 455 | # mimeit01@xmpp.hs-esslingen.de: if $comp IS set, AND the rcpt DOESN'T contain an @, then @comp is added 456 | $cnx->MessageSend('to' => $rcpt . ( ($comp && index($rcpt, "@") == -1) ? "\@$comp" : '' ), 457 | 'type' => $message_type, 458 | 'subject' => $subject, 459 | 'body' => $msg); 460 | 461 | xmpp_check_result('MessageSend', 0, $cnx); 462 | } # }}} 463 | 464 | # 465 | # xmpp_send_chatroom_message: send a message to a chatroom 466 | # input: connection, resource, subject, recipient, message 467 | # 468 | sub xmpp_send_chatroom_message ($$$$$) { # {{{ 469 | 470 | my ($cnx, $resource, $subject, $rcpt, $msg) = @_; 471 | 472 | # set the presence 473 | my $pres = new Net::XMPP::Presence; 474 | my $res = $pres->SetTo("$rcpt/$resource"); 475 | 476 | $cnx->Send($pres); 477 | 478 | # create/send the message 479 | my $groupmsg = new Net::XMPP::Message; 480 | $groupmsg->SetMessage(to => $rcpt, 481 | body => $msg, 482 | type => 'groupchat'); 483 | 484 | $res = $cnx->Send($groupmsg); 485 | xmpp_check_result ('Send', $res, $cnx); 486 | 487 | # leave the group 488 | $pres->SetPresence (Type=>'unavailable', To=>$rcpt); 489 | } # }}} 490 | 491 | # 492 | # xmpp_logout: log out from the xmpp server 493 | # input: connection 494 | # 495 | sub xmpp_logout($) { # {{{ 496 | 497 | # HACK 498 | # messages may not be received if we log out too quickly... 499 | sleep 1; 500 | 501 | my $cnx = shift; 502 | $cnx->Disconnect(); 503 | xmpp_check_result ('Disconnect', 0); # well, nothing to check, really 504 | } # }}} 505 | 506 | # 507 | # xmpp_check_result: check the return value from some xmpp function execution 508 | # input: text, result, [connection] 509 | # 510 | sub xmpp_check_result { # {{{ 511 | my ($txt, $res, $cnx)=@_; 512 | 513 | error_exit ("Error '$txt': result undefined") 514 | unless (defined $res); 515 | 516 | # res may be 0 517 | if ($res == 0) { 518 | debug_print "$txt"; 519 | # result can be true or 'ok' 520 | } 521 | elsif ((@$res == 1 && $$res[0]) || $$res[0] eq 'ok') { 522 | debug_print "$txt: " . $$res[0]; 523 | # otherwise, there is some error 524 | } 525 | else { 526 | my $errmsg = $cnx->GetErrorCode() || '?'; 527 | error_exit ("Error '$txt': " . join (': ', @$res) . "[$errmsg]", $cnx); 528 | } 529 | } # }}} 530 | 531 | # 532 | # terminate; exit the program upon TERM sig reception 533 | # 534 | sub terminate () { # {{{ 535 | debug_print "caught TERM"; 536 | xmpp_logout($main::CNX); 537 | exit 0; 538 | } # }}} 539 | 540 | # 541 | # debug_print: print the data if defined and DEBUG || VERBOSE is TRUE 542 | # input: [array of strings] 543 | # 544 | sub debug_print { # {{{ 545 | print STDERR "sendxmpp: " . (join ' ', @_) . "\n" 546 | if (@_ && ($DEBUG ||$VERBOSE)); 547 | } # }}} 548 | 549 | # 550 | # error_exit: print error message and exit the program 551 | # logs out if there is a connection 552 | # input: error, [connection] 553 | # 554 | sub error_exit { # {{{ 555 | 556 | my ($err, $cnx) = @_; 557 | print STDERR "$err\n"; 558 | xmpp_logout ($cnx) 559 | if ($cnx); 560 | 561 | exit 1; 562 | } # }}} 563 | 564 | # 565 | # usage: print short usage message and exit 566 | # 567 | sub usage () { # {{{ 568 | 569 | print STDERR 570 | "sendxmpp version $VERSION\n" . 571 | "Copyright (c) 2004 - 2005 Dirk-Jan C. Binnema\n" . 572 | "Copyright (c) 2006 - 2014 Lubomir Host\n" . 573 | "usage: sendxmpp [options] [ ...]\n" . 574 | "or refer to the the sendxmpp manpage\n"; 575 | 576 | exit 0; 577 | } # }}} 578 | 579 | # 580 | # the fine manual 581 | # 582 | =pod 583 | 584 | =head1 NAME 585 | 586 | sendxmpp - send xmpp messages from the commandline. 587 | 588 | =head1 SYNOPSIS 589 | 590 | sendxmpp [options] [ ...] 591 | 592 | sendxmpp --raw [options] 593 | 594 | =head1 DESCRIPTION 595 | 596 | sendxmpp is a program to send XMPP (Jabber) messages from the commandline, not 597 | unlike L. Messages can be sent both to individual recipients and chatrooms. 598 | 599 | =head1 OPTIONS 600 | 601 | =over 602 | 603 | =item B<-f>, B<--file> I 604 | 605 | Use I configuration file instead of F<~/.sendxmpprc> 606 | 607 | =item B<-u>, B<--username> I 608 | 609 | Use I instead of the one in the configuration file 610 | 611 | =item B<-p>, B<--password> I 612 | 613 | Use I instead of the one in the configuration file 614 | 615 | =item B<--sso> 616 | 617 | Instead of specifying username or password, attempt to use system level SSO (e.g. kerberos) if supported. 618 | 619 | =item B<-j>, B<--jserver> I 620 | 621 | Use jabber I instead of the one in the configuration file. 622 | 623 | =item B<-o>, B<--component> I 624 | 625 | Use componentname in connect call. Seems needed for Google talk. 626 | 627 | =item B<-r>, B<--resource> I 628 | 629 | Use resource I for the sender [default: 'sendxmpp']; when sending to a chatroom, this determines the 'alias' 630 | 631 | =item B<-t>, B<--tls> 632 | 633 | Connect securely, using TLS 634 | 635 | =item B<-e>, B<--ssl> 636 | 637 | Connect securely, using SSL 638 | 639 | =item B<-n>, B<--no-tls-verify> 640 | 641 | Deactivate the verification of SSL certificates. Better way is to use parameter B<--tls-ca-path> with the needed path to CA certificates. 642 | 643 | =item B<-a>, B<--tls-ca-path> 644 | 645 | Path to your custom CA certificates, so you can verificate SSL certificates during connecting. 646 | 647 | =item B<--http> 648 | 649 | Connect over HTTP, allowing the use of a proxy. 650 | 651 | =item B<-l>, B<--headline> 652 | 653 | Backward compatibility option. You should use B<--message-type=headline> instead. Send a headline type message (not stored in offline messages) 654 | 655 | =item B<--messages-type> 656 | 657 | Set type of message. Supported types are: B. Default message type is B. Headline type message can be set also with B<--headline> option, see B<--headline> 658 | 659 | =item B<-c>, B<--chatroom> 660 | 661 | Send the message to a chatroom 662 | 663 | =item B<-s>, B<--subject> I 664 | 665 | Set the subject for the message to I [default: '']; when sending to a chatroom, this will set the subject for the chatroom 666 | 667 | =item B<-m>, B<--message> I 668 | 669 | Read the message from I (a file) instead of stdin 670 | 671 | =item B<-i>, B<--interactive> 672 | 673 | Work in interactive mode, reading lines from stdin and sending the one-at-time 674 | 675 | =item B<-w>, B<--raw> 676 | 677 | Send raw XML message to jabber server 678 | 679 | =item B<-v>, B<--verbose> 680 | 681 | Give verbose output about what is happening 682 | 683 | =item B<-h>, B<--help>, B<--usage> 684 | 685 | Show a 'Usage' message 686 | 687 | =item B<-d>, B<--debug> 688 | 689 | Show debugging info while running. B: This will include passwords etc. so be careful with the output! Specify multiple times to increase debug level. 690 | 691 | =back 692 | 693 | =head1 CONFIGURATION FILE 694 | 695 | You may define a 'F<~/.sendxmpprc>' file with the necessary data for your 696 | xmpp-account. Since version 1.24 the following format is supported: 697 | 698 | username: 699 | jserver: 700 | port: 701 | password: 702 | component: 703 | 704 | 705 | Example for Google Talk servers: 706 | 707 | username: 708 | jserver: 709 | password: 710 | component: 711 | 712 | With version 1.23 and older only one-line format is supported: 713 | 714 | =over 715 | 716 | I@I I I 717 | 718 | =back 719 | 720 | e.g.: 721 | 722 | # my account 723 | alice@jabber.org secret 724 | 725 | ('#' and newlines are allowed like in shellscripts). You can add a I (or IP address) if it is different from the I part of your JID: 726 | 727 | # account with specific connection host 728 | alice@myjabberserver.com;foo.com secret 729 | 730 | You can also add a I if it is not the standard XMPP port: 731 | 732 | # account with weird port number 733 | alice@myjabberserver.com:1234 secret 734 | 735 | Of course, you may also mix the two: 736 | 737 | # account with a specific host and port 738 | alice@myjabberserver.com;foo.com:1234 secret 739 | 740 | B: for your security, sendxmpp demands that the configuration 741 | file is owned by you and readable only to you (permissions 600). 742 | 743 | =head1 EXAMPLE 744 | 745 | $ echo "hello bob!" | sendxmpp -s hello someone@jabber.org 746 | 747 | or to send to a chatroom: 748 | 749 | $ echo "Dinner Time" | sendxmpp -r TheCook --chatroom test2@conference.jabber.org 750 | 751 | or to send your system logs somewhere, as new lines appear: 752 | 753 | $ tail -f /var/log/syslog | sendxmpp -i sysadmin@myjabberserver.com 754 | 755 | NOTE: be careful not the overload public jabber services 756 | 757 | =head1 SEE ALSO 758 | 759 | Documentation for the L module 760 | 761 | The jabber homepage: L 762 | 763 | The sendxmpp homepage: L 764 | 765 | =head1 AUTHOR 766 | 767 | sendxmpp has been written by Dirk-Jan C. Binnema , and uses 768 | the L modules written by Ryan Eatmon. Current maintainer is 769 | Lubomir Host , L 770 | 771 | =cut 772 | # vim: fdm=marker fdl=0 fdc=3 773 | -------------------------------------------------------------------------------- /sendxmpp2: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | 3 | eval 'exec /usr/bin/perl -w -S $0 ${1+"$@"}' 4 | if 0; # not running under some shell 5 | 6 | # 7 | # sendxmpp2 8 | # 9 | # Developed by Lubomir Host 10 | # Copyright (c) 2014 11 | # 12 | # Homepage: http://sendxmpp.hostname.sk 13 | # 14 | # Released under the terms of the GNU General Public License v2 15 | # 16 | # Changelog: 17 | # 2014-10-13 - created 18 | # 19 | 20 | use strict; 21 | use warnings; 22 | use utf8; 23 | 24 | use Env; 25 | use AnyEvent; 26 | use AnyEvent::XMPP; 27 | use AnyEvent::XMPP::Client; 28 | #use Getopt::Long; 29 | use Config::YAML; 30 | use URI::Escape; 31 | 32 | use Data::Dumper; 33 | $Data::Dumper::Indent = 1; 34 | 35 | $ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0; 36 | 37 | use vars qw( 38 | $VERSION $DEBUG 39 | $connected 40 | ); 41 | 42 | $DEBUG = 1; 43 | $| = 1; 44 | binmode STDOUT, ":utf8"; 45 | 46 | if (scalar(@ARGV) < 1) { 47 | print STDERR "Usage: $0 user1\@jabber.org user2\@your.server.sk\n"; 48 | exit 1; 49 | } 50 | 51 | my $config = Config::YAML->new( 52 | config =>"$ENV{HOME}/.sendxmpprc", 53 | ); 54 | 55 | my $j = AnyEvent->condvar; 56 | my $cl = AnyEvent::XMPP::Client->new ( 57 | debug => ($DEBUG > 1 ? 1 : 0), 58 | tls_ctx => { verify => 0, }, # XXX: temporarily 59 | ); 60 | my $cv = AnyEvent->condvar; 61 | 62 | $cl->add_account ("$config->{username}\@$config->{jserver}", $config->{password}); 63 | AE::log info => "connecting to '$config->{username}\@$config->{jserver}' ...\n" if ($DEBUG); 64 | 65 | 66 | # 67 | # Handle XMPP - Jabber {{{ 68 | # 69 | $cl->reg_cb ( 70 | session_ready => sub { 71 | my ($cl, $acc) = @_; 72 | AE::log info => " connected";# if ($DEBUG); 73 | $connected = 1; 74 | }, 75 | message => sub { # {{{ 76 | my ($cl, $acc, $msg) = @_; 77 | # clean garbage on the of message. This solves Pidgin bug with adding 78 | # "%20%09%20%20%09%09%09%09%20%09%20%09%20%09%20%20%20%20%09%09%20%20%09%20%20%20%09%09%20%20%09%09" to the end of message 79 | my $xmsg = $msg->any_body || ''; 80 | $xmsg =~ s/[ \t]+$//g; 81 | 82 | print join("\t", $msg->type, $msg->from, $msg->to, URI::Escape::uri_escape($xmsg)), "\n"; 83 | }, # }}} 84 | contact_request_subscribe => sub { 85 | my ($cl, $acc, $roster, $contact) = @_; 86 | $contact->send_subscribed; 87 | warn "Subscribed to " . $contact->jid . "\n"; 88 | }, 89 | error => sub { 90 | my ($cl, $acc, $error) = @_; 91 | if ($error) { 92 | AE::log error => "Error encountered for " . $acc->jid . ": " . $error; 93 | } 94 | $j->broadcast; 95 | }, 96 | connect_error => sub { 97 | my ($cl, $acc, $error) = @_; 98 | if ($error) { 99 | AE::log error => "Error connecting as " . $acc->jid . ": " . $error; 100 | } 101 | $j->broadcast; 102 | }, 103 | disconnect => sub { 104 | $j->broadcast; 105 | }, 106 | ); # }}} 107 | 108 | # 109 | # Start Jabber 110 | # 111 | $cl->start; 112 | AE::log info => 'After start'; 113 | 114 | 115 | my $hdl; 116 | my $w; 117 | $w = AnyEvent->timer ( 118 | interval => 1, 119 | cb => sub { 120 | AE::log debug => "Waiting for connection ...";# if ($DEBUG); 121 | 122 | return unless ($connected); # stop timer if connected 123 | 124 | undef $w; 125 | # 126 | # Handle *STDIN {{{ 127 | # 128 | $hdl = AnyEvent->io( 129 | fh => \*STDIN, 130 | poll => 'r', 131 | cb => sub { 132 | #warn "io event <$_[0]>\n"; # will always output 133 | my $line = ; 134 | if ( defined($line) ) { 135 | chomp $line; 136 | #warn "got line <$line>\n"; 137 | foreach my $dst_jid (@ARGV) { 138 | $cl->send_message($line, $dst_jid, $config->{jid}, 'chat'); 139 | } 140 | $cv->send; 141 | } 142 | else { 143 | $cl->disconnect(); 144 | } 145 | #$hdl->push_read(line => $send_msg); 146 | }, 147 | on_error => sub { 148 | my ($hdl, $fatal, $msg) = @_; 149 | AE::log error => $msg; 150 | $hdl->destroy; 151 | #@$cv->send; 152 | }, 153 | on_eof => sub { 154 | my ($hdl, $fatal, $msg) = @_; 155 | AE::log info => 'Disconnecting from jabber'; 156 | $cl->disconnect(); 157 | $hdl->destroy; 158 | }, 159 | ); # }}} 160 | 161 | } 162 | ); 163 | 164 | 165 | $j->wait; 166 | AE::log info => 'After wait'; 167 | 168 | $cv->recv; 169 | AE::log info => 'After recv'; 170 | 171 | 172 | # vim: ts=4 173 | # vim600: fdm=marker fdl=0 fdc=3 174 | 175 | --------------------------------------------------------------------------------