Alice

 view release on metacpan or  search on metacpan

lib/Alice/Role/IRCEvents.pm  view on Meta::CPAN

  }

  $EVENTS{$name} = $code;
}

irc_event connect => sub {
  my ($self, $irc, $err) = @_;
  $irc->is_connecting(0);

  if ($irc->cl->{socket}) {
    $irc->cl->{socket}->rbuf_max(1024 * 10); # 10K max read buffer
  }

  if (defined $err) {
    $self->send_info($irc->name, "connect error: $err");
    $self->reconnect_irc($irc->name);
    return;
  }

  $self->send_info($irc->name, "connected");
  $irc->connect_time(time);

  $self->broadcast({
    type => "action",
    event => "connect",
    network => $irc->name,
  });

  my $config = $self->config->servers->{$irc->name};

  $irc->cl->register(
    $config->{nick}, $config->{username}, $config->{ircname}, $config->{password}
  );
};

irc_event registered => sub {
  my ($self, $irc) = @_;
  my $config = $self->config->servers->{$irc->name};

  $irc->reset_reconnect_count;
  $irc->cl->{connected} = 1; # AE::IRC seems broken here...

  my @commands = ();

  push @commands, map {
    my $command = $_;
    sub {
      $self->send_info($irc->name, "sending $command");
      $irc->send_raw($command);
    }
  } @{$config->{on_connect}};

  push @commands, map {
    my $channel = $_;
    sub {
      $self->send_info($irc->name, "joining $channel");
      $irc->send_srv("JOIN", split /\s+/, $channel);
    }
  } @{$config->{channels}};
    
  my $t; $t = AE::timer 1, 0.5, sub {
    if (my $command = shift @commands) {
      $command->();
    }
    else {
      undef $t;
    }
  };

  my $name = $irc->name;
  $irc->cl->enable_ping(300 => sub { $self->reconnect_irc($name) });
};

irc_event disconnect => sub {
  my ($self, $irc, $reason) = @_;

  my @windows = grep {$_->network eq $irc->name} $self->windows;
  $self->broadcast({
    type => "action",
    event => "disconnect",
    network => $irc->name,
    windows => [map {$_->serialized} @windows],
  });
  $self->remove_window($_) for map {$_->id} @windows;

  $reason = "" unless $reason;
  return if $reason eq "reconnect requested.";
  $self->send_info($irc->name, "disconnected: $reason");
  
  # TODO - Object::Event bug that prevents object from getting destroyed
  delete $irc->cl->{change_nick_cb_guard} if $irc->cl;

  $irc->cl(undef);

  $self->reconnect_irc($irc->name, 0) unless $irc->disabled;

  if ($irc->removed) {
    $self->remove_irc($irc->name);
  }
};

irc_event publicmsg => sub {
  my ($self, $irc, $channel, $msg) = @_;

  if (my $window = $self->find_window($channel, $irc)) {
    my ($nick) = split_prefix($msg->{prefix});
    my $text = $msg->{params}[1];

    return if $self->is_ignore(msg => $nick);

    $self->send_message($window, $nick, $text); 
  }
};

irc_event privatemsg => sub {
  my ($self, $irc, $nick, $msg) = @_;

  my $text = $msg->{params}[1];
  my ($from) = split_prefix($msg->{prefix});

  if ($msg->{command} eq "PRIVMSG") {

lib/Alice/Role/IRCEvents.pm  view on Meta::CPAN

      my $reason = "";

      if ($msg and $msg->{command} eq "QUIT") {
        $reason = $msg->{params}[-1] || "Quit";
      }

      $self->broadcast(
        map {$window->format_event(left => $_, $reason)} @nicks
      );
    }
  }
};

irc_event channel_topic => sub {
  my ($self, $irc, $channel, $topic, $nick) = @_;
  if (my $window = $self->find_window($channel, $irc)) {
    $topic = irc_to_html($topic, classes => 1, invert => "italic");
    $window->topic({string => $topic, author => $nick, time => time});
    $self->broadcast($window->format_event("topic", $nick, $topic));
  }
};

irc_event irc_invite => sub {
  my ($self, $irc, $msg) = @_;

  my (undef, $channel) = @{$msg->{params}};
  my ($from) = split_prefix($msg->{prefix});

  my $message = "$from has invited you to $channel on ".$irc->name;
  $self->announce($message);
};

irc_event 464 => sub{
  my ($self, $irc, $msg) = @_;
  $self->disconnect_irc($irc->name, "bad USER/PASS")
};

irc_event [qw/001 305 306 401 471 473 474 475 477 485 432 433/] => sub {
  my ($self, $irc, $msg) = @_;
  $self->send_info($irc->name, $msg->{params}[-1]);
};

irc_event [qw/372 377 378/] => sub {
  my ($self, $irc, $msg) = @_;
  $self->send_info($irc->name, $msg->{params}[-1], mono => 1);
};

sub reconnect_irc {
  my ($self, $name, $time) = @_;
  my $irc = $self->get_irc($name);
  throw InvalidNetwork "$name isn't one of your networks" unless $irc;

  my $interval = time - $irc->connect_time;

  if ($interval < 15) {
    $time = 15 - $interval;
    $self->send_info($irc->name, "last attempt was within 15 seconds, delaying $time seconds")
  }

  if (!defined $time) {
    # increase timer by 15 seconds each time, until it hits 5 minutes
    $time = min 60 * 5, 15 * $irc->reconnect_count;
  }

  $self->send_info($irc->name, "reconnecting in $time seconds");
  $irc->reconnect_timer(AE::timer $time, 0, sub {$self->connect_irc($name)});
}

sub disconnect_irc {
  my ($self, $name, $msg) = @_;
  my $irc = $self->get_irc($name);
  throw InvalidNetwork "$name isn't one of your networks" unless $irc;

  if ($irc->reconnect_timer) {
    $self->cancel_reconnect($name);
    return;
  }

  throw DisconnectError "$name is already disconnected" if $irc->is_disconnected;

  $self->send_info($irc->name, "disconnecting: $msg") if $msg;
  $irc->is_connecting(0);
  $irc->disabled(1);
  $msg ||= $self->config->quitmsg;
  $irc->cl->disconnect($msg);
}

sub cancel_reconnect {
  my ($self, $name) = @_;
  my $irc = $self->get_irc($name);
  throw InvalidNetwork "$name isn't one of your networks" unless $irc;

  $self->send_info($irc->name, "canceled reconnect");
  $self->broadcast({
    type => "action",
    event => "disconnect",
    network => $irc->name,
    windows => [], #shouldn't be any windows if we're not connected.
  });
  $irc->reconnect_timer(undef);
  $irc->reset_reconnect_count;
}

sub connect_irc {
  my ($self, $name) = @_;
  my $irc = $self->get_irc($name);

  throw InvalidNetwork "$name isn't one of your networks" unless $irc;
  throw ConnectError "$name is already connected" if $irc->is_connected;
  throw ConnectError "$name is already connecting" if $irc->is_connecting;

  $irc->reconnect_timer(undef);
  my $config = $self->config->servers->{$irc->name};
 
  # some people don't set these, wtf
  if (!$config->{host} or !$config->{port}) {
    $self->send_info($irc->name, "can't connect: missing either host or port");
    return;
  }

  my $events = $self->build_events($irc);
  $irc->new_client($events, $config);
  $irc->disabled(0);
  $irc->increase_reconnect_count;
   
  $self->send_info($irc->name, "connecting (attempt " . $irc->reconnect_count .")");
  
  $irc->is_connecting(1);
  $irc->cl->connect($config->{host}, $config->{port});
}

1;



( run in 1.085 second using v1.01-cache-2.11-cpan-39bf76dae61 )