User Control Panel
Advertisements

HELP US, HELP YOU!

Sending messages with Net::OSCAR

 
Post new topic   Reply to topic    Bot Depot Forum Index -> AIM Protocol & questions
View unanswered posts
Author Message
pemerson
Newbie
Newbie


Joined: 17 Aug 2005
Posts: 3

Reputation: 8.8Reputation: 8.8Reputation: 8.8Reputation: 8.8Reputation: 8.8Reputation: 8.8Reputation: 8.8Reputation: 8.8

PostPosted: Wed Aug 17, 2005 10:58 pm    Post subject: Sending messages with Net::OSCAR Reply with quote

I'd like to be able to send messages using Net::OSCAR that do not depend on responding to an incoming message. My simple "respond back to sender" code works fine, but "just send this message out" code does not. Any pointers would be appreciated.

Pete

Code:
#!/usr/bin/perl
use strict;
use Net::OSCAR qw(:standard);

my $screenname = 'bot_username';
my $password = 'bot_password';
my $destination = 'destination_username';

my $oscar = Net::OSCAR->new();
$oscar->set_callback_im_in(\&im_in);
$oscar->signon($screenname, $password);
print "Username $screenname logged on.\n";
# Bot never appears to be "online", though.

#auto_responder(); # This works fine when uncommented
send_one_message('hello'); # This does not work.

sub send_one_message {
        my ($message) = @_;
        print "$destination: $message\n"; # This prints out as expected
        $oscar->send_im($destination, $message, 0); # nothing happens
}

sub auto_responder {
        while (1) {
                $oscar->do_one_loop();
        }
}

sub im_in {
        my($oscar, $sender, $message, $is_away) = @_;
        print "Received $message from $sender. Sending it right back.\n";
        print "$sender: $message\n";
        $oscar->send_im($destination, $message, 0);
}
Back to top
Mojave
Almost An Agent
Almost An Agent


Joined: 01 Nov 2003
Posts: 1434

Reputation: 66.4

PostPosted: Wed Aug 17, 2005 11:10 pm    Post subject: Reply with quote

Your "auto_responder" code runs the oscar loop, which is required to process incoming messages from the server and by messages I don't just mean messages from users, but server messages (setting up buddy lists, pings maybe, etc). When you comment that code out, you effectively shut down the connection. Try something like this:

Code:
sub auto_responder {
  my $i = 0;
        while (1) {
  $i++;
  if( $i == 1 )  { &send_one_message('hello'); }
                $oscar->do_one_loop();
        }
}


I use $i so that we only send out one message. This is a sort of clunky way to do it, but it should work. A better solution is to tell us why you are trying to send messages that are NOT in response to an incoming message or some other event.
Back to top
pemerson
Newbie
Newbie


Joined: 17 Aug 2005
Posts: 3

Reputation: 8.8Reputation: 8.8Reputation: 8.8Reputation: 8.8Reputation: 8.8Reputation: 8.8Reputation: 8.8Reputation: 8.8

PostPosted: Thu Aug 18, 2005 12:12 am    Post subject: Reply with quote

Mojave wrote:
Your "auto_responder" code runs the oscar loop, which is required to process incoming messages from the server and by messages I don't just mean messages from users, but server messages (setting up buddy lists, pings maybe, etc). When you comment that code out, you effectively shut down the connection. Try something like this:


You nailed it. I'm trying to tail a file and when new lines come in, send out messages. I wasn't calling do_one_loop() enough to fully sign on. Debug mode helped a little, too. A followup:

If I want to be able to be more "botlike" and reply to messages etc. etc., this code won't work, since once it's signed on it will only do_one_loop() when a new line comes in in the log file. Is the solution to re-tail my file every time through my loop ($curr = `tail -n1 $log_file`), detecting changes (if $curr ne $last), so that do_one_loop() is executed many times? Or is there a smarter way?

Thanks for your help! Code below in case it helps someone else out.

Pete

Code:
#!/usr/bin/perl
use strict;
use Net::OSCAR qw(:standard);

my $log_file = './logfile.txt';
my $screenname = 'botusername';
my $password = 'botpass';
my $destination = 'enduser';

my $oscar = Net::OSCAR->new();
$oscar->set_callback_im_in(\&im_in);
$oscar->set_callback_signon_done(\&signon_done);
$oscar->loglevel(5);

my $signed_on = 0;
$oscar->signon($screenname, $password);
$oscar->set_visibility(VISMODE_PERMITALL);
$oscar->set_stealth(0);

while(!$signed_on) {
        $oscar->do_one_loop();
}

open INFILE, "tail -n0 -f $log_file |" or die "Can't open $log_file: $!";
while (<INFILE>) {
        $oscar->do_one_loop();
        chomp;
        print "$destination: $_\n";
        $oscar->send_im($destination, $_, 0);
}

sub im_in {
        my($oscar, $sender, $message, $is_away) = @_;
        print "Received $message from $sender. Discarding it for now.\n";
}

sub signon_done {
        print "Bot logged on.\n";
        $signed_on = 1;
}
Back to top
Mojave
Almost An Agent
Almost An Agent


Joined: 01 Nov 2003
Posts: 1434

Reputation: 66.4

PostPosted: Thu Aug 18, 2005 3:53 am    Post subject: Reply with quote

OK, so what you're trying to do is be notified each time a new line is added to a log file? But with Oscar, you MUST let the loop run at all times. So you need to rework your code. Run the loop as normal with a while( 1 ) and inside that you have oscar's do loop and you check to see if the file has been updated, if it has do a tail and get only the last line and send it. Does that make sense?

You might want to see how fast ocsar's do loop is running and do the file check less often, say once every 15 seconds or so, depending on how fast you need the notification.
Back to top
pemerson
Newbie
Newbie


Joined: 17 Aug 2005
Posts: 3

Reputation: 8.8Reputation: 8.8Reputation: 8.8Reputation: 8.8Reputation: 8.8Reputation: 8.8Reputation: 8.8Reputation: 8.8

PostPosted: Thu Aug 18, 2005 4:06 am    Post subject: Reply with quote

Mojave wrote:
You might want to see how fast ocsar's do loop is running and do the file check less often, say once every 15 seconds or so, depending on how fast you need the notification.


That's exactly the conclusion I came to. I'm actually tailing enough lines so that I know that I'll get some overlap, and then storing those lines in a hash and checking to see whether I've sent those lines or not. That way if more than one line need to be sent, I'll know it.

Any suggestions on how to throttle outgoing messages? I think if I send too many at once, I'll get warned and shut down. I'm putting a sleep(1) after every message sent, but I don't know if that's sufficient or not.

Thanks a lot for the help! I'm afraid now that I understand what's going on I'm going to have feature creep. Smile

Pete
Back to top
Mojave
Almost An Agent
Almost An Agent


Joined: 01 Nov 2003
Posts: 1434

Reputation: 66.4

PostPosted: Thu Aug 18, 2005 5:53 am    Post subject: Reply with quote

You don't want to use sleep. Sleep freezes the program for that number of seconds, which also freezes the oscar loop. Many people fall into the trap of using sleep to slow things down. If this bot is only going to be used by one person, you might be able to get away with it, but if you have hundreds of users and say 20 of them are using your bot at the same time, you'll be sleeping for 20 seconds at a time, which is very bad.

AIM bots have an inherent problem due to rate limits. Unless you're willing to pay AOL $100k to turn off rate limits for your bot, you're out of luck. You need to wait a minimum of 3 seconds in between outgoing messages. If you're bot is warned, you need to wait longer depending on the warning rate (hmm, does AIM even have warnings anymore?). Anyhow, if you have 20 simultaneous users, that means that they will be waiting at least a minute to get a reply from the bot. This is why so many developers have dropped AIM bots and moved to MSN or Jabber, etc.

Anyhow, now that I've given this long boring lecture, how do you deal with it? You need a message queue. Instead of sending out a message immediately, you put the message in the queue. Then in your oscar loop, every 3+ seconds, you get the first message in the queue, send it and remove it from the queue. This is the best way to handle the situation.

And as you get more into feature creep, you'll find a message queue is a great thing, because you can control message priority, for example moving messages to bot admins higher in the queue, etc.
Back to top
Cer
Upgraded Agent
Upgraded Agent


Joined: 03 Feb 2004
Posts: 3776
Location: Michigan
Reputation: 146.9
votes: 4

PostPosted: Thu Aug 18, 2005 6:07 pm    Post subject: Reply with quote

A simple way to find out if a file has been updated is do a stat() on it. The 9th array item is the time() the file was last updated, so...

Code:
my @stats = stat('file.txt');
my $last = $stats[9];

while (1) {
   $aim->do_one_loop();

   my @stats = stat('file.txt');
   my $now = $stats[9];
   if ($now != $last) {
      $last = $now;

      # Send an IM and stuff here
   }
}


Also, if you don't know how to make a message queue, I posted a rough tutorial once of how I do them for my bots: http://www.aichaos.com/YaBB/YaBB.cgi?board=tutorials;action=display;num=1116768441

_________________
Current Site (2008) http://www.cuvou.com/
Back to top
Display posts from previous:   
Post new topic   Reply to topic    Bot Depot Forum Index -> AIM Protocol & questions All times are GMT
Page 1 of 1

 



Protected by phpBB Security phpBB-TweakS
phpBB Security Has Blocked 9 Exploit Attempts.
Antispam Captcha Mod by phpbb-security.com
Powered by phpBB © 2001, 2005 phpBB Group