Perl Irssi scripting: How to send msg to a specific channel? - perl

I need to establish this single task with Irssi Perl script. I have my own channel and I want to sent msg directly to that channel in certain scenarios.
My experience with Perl is quite limited so I haven't got this one. I am confused how to manage different chatnets and channels in Irssi Perl scripting. So how I can send message for example channel #testchan#Quakenet for example?
Test one:
server->command("^MSG $info{'#testchan'} $info{'Test message.'}");
Test two (tuto about scripting):
sub away_describe_pub_channels {
my($net, $channel) = #_;
my ($text) = #_;
my $c = Irssi::server_find_chatnet("QuakeNet")->channel_find("testchan");
$c->command("DESCRIBE $channel $text")
}

here is an example is used for a bot :)
#==========================BEGINNING OF PARMS======================================
#name of the channels where this feature will be used
my #channels = ("foo","bar");
#the public commands
#help
my $cmd_help = '!help';
#new ticket
my $cmd_newticket = "!stack";
my %url_newticket = ( 'foo'=>{url=>"http://stackoverflow.com/questions/ask"},
'bar'=>{url=>"http://https://github.com/repo/project/issues/new"}
sub bootstrap {
my ($server, $msg, $nick, $address, $target) = #_;
#lowercase of the channel name in case this one will be registered in camelCase ;)
$target = lc $target;
foreach my $channel (#channels) {
if ( $target eq "#".$channel) {
#split the line first peace the command second the rest
my ($cmd,$line) = split / /,$msg,2;
if ($cmd =~ $cmd_help) {
$server->command("MSG ". $nick ." Here are the available commands : !stack");
} elsif ($cmd eq $cmd_newticket) {
my $h = $url_newticket{$channel};
$server->command("MSG $target submit an issue/a ticket $h->{'url'}");
}
}
}
}
#let's add the sub as a signal and let's play
Irssi::signal_add_last('message public', 'bootstrap');
Hope this could help

Related

print out email on terminal using data::dumper

I am not understanding how to use Data::Dumper even after reading the Perl doc and looking at other scripts in git. I see lots of examples online dealing with hashes, but I didn't think that quite fit with what I need to do.
I am creating a script to send emails to managers or teams regarding terminated employees. I was told to add print Dumper $email to my code so that when --dry_run option is used, we could see on the terminal a printout of what the email would look like. --dry_run would also ensure that the email isn't actually sent. When I run perl <script> --dry_run, nothing happens. Maybe I need to do something along the lines of $d = Data::Dumper->new(?
Here is a snippet of my code:
#!/usr/bin/perl
use strict;
use warnings;
use NIE::Email;
use Data::Dumper;
use List::Util qw(any);
use Getopt::Long;
Getopt::Long::Configure qw(gnu_getopt);
my ($qa, $verbose, $dry_run, $help, $dbh);
GetOptions(
'qa' => \$qa,
'verbose|v' => \$verbose,
'dry_run' => \$dry_run,
'help|h' => \$help
);
#Generate email here
sub mail_func {
print "Prepare email\n" if $verbose;
my $n = shift; #user
my $i = shift; #ips
my $t = shift; #testnets
my $m = shift; #managers (multiple if owner is undef)
my #to_list; # send to field
foreach my $value (values %{$t}) {
if ($value ne 'lab#abc.com') { #don't send this email to lab#
if (any { $value eq $_ } #to_list) { #check not already listed
next;
}
else { push(#to_list, $value); }
}
}
foreach my $key (keys %{$m}) {
if ($key ne 'def') {
if (any { $key eq $_ } #to_list) {
next;
}
else { push(#to_list, $key . '#abc.com'); }
}
}
my #body;
while (my ($key, $value) = each %{$i}) {
my $b = "IP " . $key . " : Testnet " . $value . "\n";
push(#body, $b);
}
my $sub1 = "Ownership needed!";
my $sub2 = "Ownership needed script special case";
my $email;
#Email testnet group (if not lab) as well as manager of term employee
if (#to_list) {
$email = NIE::Email->new(
From => 'do-not-reply#abc.com',
To => join(',', #to_list),
'Reply-to' => 'def#abc.com',
Subject => $sub1,
);
$email->data(
"Good Day, \n\n The below machines need claimed as their previous"
. " owner, $n, is showing up as no longer with the company. \n"
. "Please visit website to change"
. " ownership of these machhines. \n\n"
. "#body \n\n"
. "If you have already requested an ownership change for these"
. " machines, please disregard this message."
. "\n\n Thank you \n -Lab team \n\n"
. "This script is under active development and could contain"
. " bugs, so please speak up if you have doubts or something "
. "looks strange."
. "\n Script name: lab_ownership_needed_email");
if ($dry_run) {print Dumper($email);}
else {$email->send();}
}
Any help in understanding how to use this for my purpose would be greatly appreciated. Thank you.
Reverted to original, re-added in code, re-ran the script, and it works.
The above code is correct as is.
Thanks to simbabque who stated the code looked correct in the first place.

How to get status update in NCBI standalone BLAST?

For example, I am running standalone Blast+ for thousands of EST sequences with remote (NCBI) server. I am not getting any status message like 15 of 100 sequence is running. Is it possible to get any status message like that? or any other way to send one after another sequence using perl scripts?
Many thanks!
I suggest using Bioperl (http://metacpan.org/pod/BioPerl) and the Bio::Tools::Run::RemoteBlast module. See http://metacpan.org/pod/Bio::Tools::Run::RemoteBlast and here is the code example they give in the RemoteBlast.pm module
while (my $input = $str->next_seq()){
#Blast a sequence against a database:
#Alternatively, you could pass in a file with many
#sequences rather than loop through sequence one at a time
#Remove the loop starting 'while (my $input = $str->next_seq())'
#and swap the two lines below for an example of that.
my $r = $factory->submit_blast($input);
#my $r = $factory->submit_blast('amino.fa');
print STDERR "waiting..." if( $v > 0 );
while ( my #rids = $factory->each_rid ) {
foreach my $rid ( #rids ) {
my $rc = $factory->retrieve_blast($rid);
if( !ref($rc) ) {
if( $rc < 0 ) {
$factory->remove_rid($rid);
}
print STDERR "." if ( $v > 0 );
sleep 5;
} else {
my $result = $rc->next_result();
#save the output
my $filename = $result->query_name()."\.out";
$factory->save_output($filename);
$factory->remove_rid($rid);
print "\nQuery Name: ", $result->query_name(), "\n";
while ( my $hit = $result->next_hit ) {
next unless ( $v > 0);
print "\thit name is ", $hit->name, "\n";
while( my $hsp = $hit->next_hsp ) {
print "\t\tscore is ", $hsp->score, "\n";
}
}
}
}
}
}
Look at the method retrieve_blast (http://metacpan.org/pod/Bio::Tools::Run::RemoteBlast#retrieve_blast). It will return a status code to let you know if the blast job is finished. Let me know if you have more questions and I will try to clarify further.
Paul

How to alter email2sms script to search for qualifier WARNING: blatant Plagiarism

I found a perl script that checks an email account and forwards the contents to a gsm phone. It uses below code to determine the body of the email. This can be different for each email package so doesn't really work. I was going to have a # at the beginning of the email body instead, how would go about doing this?
sub ProcessEmail
{
# Assign parameter to a local variable
my (#lines) = #_;
my $body_start = 'FALSE';
$sms_body = "";
# Declare local variables
my ($from, $line, $sms_to);
# Check each line in the header
foreach $line (#lines)
{
print $line;
if($line =~ m/^From: (.*)/)
{
# We found the "From" field, so let's get what we need
$from = $1;
$from =~ s/"|<.*>//g;
$from = substr($from, 0, 39); # This gives us the 'From' Name
}
elsif( $line =~ m/^Subject: (.*)/)
{
# We found the "Subject" field. This contains the No to send the SMS to.
$sms_to = $1;
$sms_to = substr($sms_to, 0, 29);
if ($sms_to =~ /^[+]?\d+$/ ) # here we check if the subject is a no. If so we proceed.
{
print "Got email. Subject is a number. Processing further\n";
}
else #Otherwise we delete the message and ignore it.
{
print "Got email. Subject is NOT a number. Ignoring it. \n";
return;
}
}
elsif(( $line =~ m/^Envelope-To:/)||($body_start eq 'TRUE')) # This is the last line in the email header
{ # after this the body starts
if($body_start ne 'FALSE')
{
$sms_body = $sms_body . $line;
}
$body_start='TRUE';
}
}
# At this point we know the Subject, From and Body.
# So we can send the SMS out to the provided no.
$sms_body = "SMS via Email2SMS from $from: " . $sms_body;
# You can only send SMS in chunks of 160 chars Max according to gnokii.
# so breaking the body into chunks of 160 and sending them 1 at a time.
print $sms_to;
print $sms_body;
This is something you'll be able to avoid re-inventing by using a module from CPAN to handle it.
At a quick glance, Mail::Message::Body from the Mail::Box distribution looks like it should probably do the job. See also Email::Abstract.
Altered to search for a string that was specific to the mailer. Nasty and will only work from a specific mail sender, but it worked

Perl / Net::SNMP : script too slow, need to optimize

I would like to optimize my perl script because it is a bit slow for displaying informations about the network.
I don't know what can be changed or ameliorated to boost the script execution.
I manipulate several hashes, to get : mac add, index, etc... I think it's a bit heavy, but no other choice.
Moreover, I do a lot of SNMP request and the handling of errors is maybe not great.
I copy/paste my script and its module.
Thanks in advance for reading my code.
It takes in args :
interface name (ex. FastEthernet0/9 or FastEthernet0/1...)
hostname : ip of the switch
community (often =public)
Hope this is comprehensible.
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
use SnmpUtil;
use AdresseMac;
use Net::SNMP;
use Net::SNMP::Interfaces;
my $ifname;
my $hostname;
my $community;
my $version = 1;
GetOptions( "ifname=s" => \$ifname,
"host=s" => \$hostname,
"community=s" => \$community,
"protocol:s" => \$version);
my $interfaces = Net::SNMP::Interfaces->new(Hostname => $hostname, Community => $community);
my $inter = $interfaces->interface($ifname);
#Get interface $ifname
my $ifindex = $inter->index();
#Vitesse
my $vitesse = $inter->ifHighSpeed();
#Alias
my $ifalias = $inter->ifAlias();
#Seek for VLANs
my $vlan_trouve;
#Listing all VLANS
my $vmVlan = "1.3.6.1.4.1.9.9.68.1.2.2.1.2"; #OID of vlan table
my $vlans = SnmpUtil->new($hostname, $community);
my %vl = $vlans->requeteTable($vmVlan);
$vlans->deconnexion();
#Get the good VLAN corresponding to index interface
$vlan_trouve = $vl{$ifindex};
#Listing : port VLAN <-> #mac
my $dot1dTpFdbAddress = "1.3.6.1.2.1.17.4.3.1.1";
my $dot = SnmpUtil->new($hostname, $community."#".$vlan_trouve);
my %dot1address = $dot->requeteTable($dot1dTpFdbAddress);
#Listing : numPortBridge <-> port VLAN
my $dot1dTpFdbPort = "1.3.6.1.2.1.17.4.3.1.2";
my %portdot = reverse($dot->requeteTable($dot1dTpFdbPort));
#Listing : num Port bridge <-> ID port switch
my $dot1dBasePortIfIndex = "1.3.6.1.2.1.17.1.4.1.2";
my %dotindex = reverse($dot->requeteTable($dot1dBasePortIfIndex));
#Duplex (auto, half or full)
my $oid_cisco_duplex = "1.3.6.1.2.1.10.7.2.1.19.".$ifindex;
my $duplex = $dot->requete($oid_cisco_duplex);
if ($duplex==1) {
$duplex= "Auto";
}
elsif ($duplex==2) {
$duplex = "Half";
}
elsif ($duplex==3) {
$duplex= "Full";
}
#Close connection
$dot->deconnexion();
#Go back up, to find mac add
my $numportbridge = $dotindex{$ifindex};
if (!defined($numportbridge)) {
print "Erreur : $ifindex not found in list : num Port bridge <-> ID port switch\n";
exit 2;
}
my $portVlan = $portdot{$numportbridge};
if (!defined($portVlan)) {
print "Erreur : $numportbridge not found in list : numPortBridge <-> ports du VLAN\n";
exit 3;
}
my $add = uc($dot1address{$portVlan});
if (!defined($add)) {
print "Erreur : $portVlan not found in list : ports du VLAN <-> \#mac\n";
exit 4;
}
$add =~ s/^0X//g;
printf "<b>Port : $ifname</b><br/>Index $ifindex on VLAN : $vlan_trouve<br/>\#mac : $add<br/>Speed=$vitesse Mbps Alias=$ifalias<br/>Duplex: $duplex\n";
Here's SnmpUtil.pm :
#!/usr/bin/perl
use strict;
use warnings;
use Net::SNMP;
package SnmpUtil;
our ($session, $error);
sub new {
my ($classe, $hostname, $community) = #_;
my $this = {
"hostname" => $hostname,
"community" => $community
};
bless($this, $classe);
$this->{connexion} = $this->connexion;
return $this;
}
sub connexion {
my ($this) = #_;
($session, $error) = Net::SNMP->session(
-hostname => $this->{hostname},
-community => $this->{community},
-version => "1",
-timeout => 3,
);
request_error_connexion() if (!defined($session));
}
sub request_error_connexion {
my ($this) = #_;
print "Erreur : can't connect to host\n";
print "Erreur : $error\n";
if ($error =~ /The argument "-community" is unknown/)
{
# protocol SNMP version 3 not working
exit 3; # code ret final = 3*256 = 768
}
else
{
exit 1; # code retour final = 1*256 = 256
}
}
sub request_error {
my ($this) = #_;
print "Error : no answer from host\n";
printf "Erreur : %s\n",$session->error;
if ($session->error =~ /No response from remote host/)
{
#host ok, bad community or host refuse connection
$session->close;
exit 2; # code retour final = 2*256 = 512
}
else
{
#can not find table
$session->close;
exit 4; # code retour final = 4*256 = 1024
}
}
sub requeteTable {
my ($this, $oid) = #_;
my $result = $session->get_table( -baseoid => $oid );
request_error() if (!defined($result));
my %tab = ();
foreach my $i (Net::SNMP::oid_lex_sort(keys %{$result})) {
my $index = $i;
$index =~ s/$oid.//;
$tab{ $index } = $result->{$i};
#print $index."--".$result->{$i}."\n";
}
return %tab;
}
sub requete {
my ($this, $oid) = #_;
my $result = $session->get_request($oid);
request_error() if (!defined($result));
return $result->{$oid};
}
sub deconnexion {
my ($this) = #_;
$session->close();
}
1;
AdresseMac.pm module is useless, it's just to convert dec to hex & vice-versa.
Thanks for your help,
big reward for the one who find optimization ;)
PS: forgot to say, I work on cisco switch 2960.
You may not like this answer, but one of the reasons that Net-SNMP supports a perl module (called just SNMP) written using C-bindings rather than the all-in-perl module implementation done in Net::SNMP is that the C-bindings are significantly faster. Giovanni Marzot, who wrote the initial implementation of the Net-SNMP C-binding binding, measured the C/perl-binding implementation to be up to 10 times faster than the all-perl version. And if you starting getting into the authenticated/encrypted SNMPv3 then it gets even faster. I don't know if this is the source of your problems, however. Just a data point. A perl profiler would really let you know.
Another point to consider: if you're querying lots of hosts, think about architecting your code so that you can send multiple queries out at a time using asynchronous requests and using GetBulk requests using SNMPv2c as well. These two optimizations will greatly increase the speed as well.
Updated with links per request:
Net-SNMP: http://www.net-snmp.org/ and download: http://www.net-snmp.org/download.html .
The net-snmp toolkit comes with it's perl module. Configure Net-SNMP using --with-perl-modules
Net-SNMP's perl FAQ: http://www.net-snmp.org/wiki/index.php/FAQ:Perl
A mildly out of date man page: http://metacpan.org/pod/SNMP
Note that Net-SNMP has a gettable() function you may be interested in that does lots of optimizations.

How can I make my Perl Jabber bot an event-driven program?

I'm trying to make a Jabber bot and I am having trouble keeping it running while waiting for messages. How do I get my script to continuously run? I have tried calling a subroutine that has a while loop that I, in theory, have set up to check for any messages and react accordingly but my script isn't behaving that way.
Here is my source: http://pastebin.com/03Habbvh
# set jabber bot callbacks
$jabberBot->SetMessageCallBacks(chat=>\&chat);
$jabberBot->SetPresenceCallBacks(available=>\&welcome,unavailable=>\&killBot);
$jabberBot->SetCallBacks(receive=>\&prnt,iq=>\&gotIQ);
$jabberBot->PresenceSend(type=>"available");
$jabberBot->Process(1);
sub welcome
{
print "Welcome!\n";
$jabberBot->MessageSend(to=>$jbrBoss->GetJID(),subject=>"",body=>"Hello There!",type=>"chat",priority=>10);
&keepItGoing;
}
sub prnt
{
print $_[1]."\n";
}
#$jabberBot->MessageSend(to=>$jbrBoss->GetJID(),subject=>"",body=>"Hello There! Global...",type=>"chat",priority=>10);
#$jabberBot->Process(5);
#&keepItGoing;
sub chat
{
my ($sessionID,$msg) = #_;
$dump->pl2xml($msg);
if($msg->GetType() ne 'get' && $msg->GetType() ne 'set' && $msg->GetType() ne '')
{
my $jbrCmd = &trimSpaces($msg->GetBody());
my $dbQry = $dbh->prepare("SELECT command,acknowledgement FROM commands WHERE message = '".lc($jbrCmd)."'");
$dbQry->execute();
if($dbQry->rows() > 0 && $jbrCmd !~ /^insert/si)
{
my $ref = $dbQry->fetchrow_hashref();
$dbQry->finish();
$jabberBot->MessageSend(to=>$msg->GetFrom(),subject=>"",body=>$ref->{'acknowledgement'},type=>"chat",priority=>10);
eval $ref->{'command'};
&keepItGoing;
}
else
{
$jabberBot->MessageSend(to=>$msg->GetFrom(),subject=>"",body=>"I didn't understand you!",type=>"chat",priority=>10);
$dbQry->finish();
&keepItGoing;
}
}
}
sub gotIQ
{
print "iq\n";
}
sub trimSpaces
{
my $string = $_[0];
$string =~ s/^\s+//; #remove leading spaces
$string =~ s/\s+$//; #remove trailing spaces
return $string;
}
sub keepItGoing
{
print "keepItGoing!\n";
my $proc = $jabberBot->Process(1);
while(defined($proc) && $proc != 1)
{
$proc = $jabberBot->Process(1);
}
}
sub killBot
{
print "killing\n";
$jabberBot->MessageSend(to=>$_[0]->GetFrom(),subject=>"",body=>"Logging Out!",type=>"chat",priority=>10);
$jabberBot->Process(1);
$jabberBot->Disconnect();
exit;
}
POE has some pretty good event frameworks. I don't know how good the one for Jabber (POE::Component::Jabber) is, but it's probably worth looking at.
AnyEvent::XMPP is ridiculously comprehensive, and, since it uses AnyEvent, can be run in any event driven application with a supported loop (AnyEvent's own, Event, EV, Tk, Glib/Gtk, even POE).
I think you can make your example work by doing this:
0 while $jabber->Process
Having said that, I would strongly recommend using a proper Event handling framework such as AnyEvent (my personal favorite) or POE (the traditional choice).