[839] in BarnOwl Developers
[D-O-H] r831 - in branches/barnowl_unicode: . owl owl/perl/lib/BarnOwl owl/perl/modules/IRC/lib/BarnOwl/Message owl/perl/modules/IRC/lib/BarnOwl/Module owl/perl/modules/IRC/lib/BarnOwl/Module/IRC
daemon@ATHENA.MIT.EDU (asedeno@MIT.EDU)
Thu Oct 29 18:10:16 2009
Resent-From: nelhage@mit.edu
Resent-To: barnowl-dev-mtg@charon.mit.edu
To: dirty-owl-hackers@mit.edu
From: asedeno@MIT.EDU
Reply-to: dirty-owl-hackers@MIT.EDU
Date: Fri, 11 Jan 2008 14:28:37 -0500 (EST)
Author: asedeno
Date: 2008-01-11 14:28:36 -0500 (Fri, 11 Jan 2008)
New Revision: 831
Modified:
branches/barnowl_unicode/
branches/barnowl_unicode/owl/message.c
branches/barnowl_unicode/owl/perl/lib/BarnOwl/ModuleLoader.pm
branches/barnowl_unicode/owl/perl/modules/IRC/lib/BarnOwl/Message/IRC.pm
branches/barnowl_unicode/owl/perl/modules/IRC/lib/BarnOwl/Module/IRC.pm
branches/barnowl_unicode/owl/perl/modules/IRC/lib/BarnOwl/Module/IRC/Connection.pm
branches/barnowl_unicode/owl/perlglue.xs
branches/barnowl_unicode/owl/perlwrap.pm
branches/barnowl_unicode/owl/variable.c
branches/barnowl_unicode/owl/zephyr.c
Log:
Merged revisions 812-830 via svnmerge from
file:///afs/sipb.mit.edu/project/barnowl/src/svn/trunk
........
r814 | nelhage | 2008-01-09 23:14:20 -0500 (Wed, 09 Jan 2008) | 3 lines
r27181@lunatique: nelhage | 2008-01-09 23:13:52 -0500
Implement /part and /names. We don't parse the /names response yet
........
r815 | nelhage | 2008-01-10 00:12:52 -0500 (Thu, 10 Jan 2008) | 1 line
Show PART and JOIN messages
........
r816 | nelhage | 2008-01-10 00:13:11 -0500 (Thu, 10 Jan 2008) | 2 lines
Show the channel in LOG{IN,OUT} messages
........
r817 | geofft | 2008-01-10 00:32:44 -0500 (Thu, 10 Jan 2008) | 6 lines
A (broken) attempt at handling motds and other IRC admin messages
Export owl_function_beep() to Perl, and ring the bell on receiving a message
containing your nick (on that network)
........
r818 | nelhage | 2008-01-10 01:01:32 -0500 (Thu, 10 Jan 2008) | 2 lines
Document the IRC variables
........
r819 | nelhage | 2008-01-10 01:02:06 -0500 (Thu, 10 Jan 2008) | 3 lines
Handle recreation of an existing variable better. Copy over the
default and docstrings, but preserve the old value.
........
r820 | nelhage | 2008-01-10 01:16:33 -0500 (Thu, 10 Jan 2008) | 2 lines
Handle zephyrs to users on non -c message better (fixes #39)
........
r821 | nelhage | 2008-01-10 01:28:59 -0500 (Thu, 10 Jan 2008) | 2 lines
sprintf -> snprintf
........
r822 | nelhage | 2008-01-10 01:43:11 -0500 (Thu, 10 Jan 2008) | 2 lines
Make :reload-modules work correctly with PARs
........
r823 | nelhage | 2008-01-10 15:47:00 -0500 (Thu, 10 Jan 2008) | 1 line
Require 'isprivate' to be a literal 'true', not merely present for a message to be considered private
........
r824 | nelhage | 2008-01-10 15:48:00 -0500 (Thu, 10 Jan 2008) | 2 lines
Document (nearly) every public function in the BarnOwl:: namespace
........
r825 | nelhage | 2008-01-10 15:49:27 -0500 (Thu, 10 Jan 2008) | 2 lines
`beep' is already a barnowl command, so this binding is superfluous
........
r826 | nelhage | 2008-01-10 15:58:49 -0500 (Thu, 10 Jan 2008) | 1 line
strip IRC coloring from IRC messages
........
r827 | nelhage | 2008-01-10 17:22:46 -0500 (Thu, 10 Jan 2008) | 2 lines
Document ::Hook and ::Hooks
........
r828 | geofft | 2008-01-10 21:01:27 -0500 (Thu, 10 Jan 2008) | 1 line
Move comment around so that perlglue.xs compiles.
........
r829 | nelhage | 2008-01-10 23:25:27 -0500 (Thu, 10 Jan 2008) | 1 line
doc nits
........
r830 | nelhage | 2008-01-11 01:38:50 -0500 (Fri, 11 Jan 2008) | 2 lines
Handle `nickinuse' errors and disconnects
........
Property changes on: branches/barnowl_unicode
___________________________________________________________________
Name: svnmerge-integrated
- /trunk:1-811
+ /trunk:1-830
Modified: branches/barnowl_unicode/owl/message.c
===================================================================
--- branches/barnowl_unicode/owl/message.c 2008-01-11 06:38:50 UTC (rev 830)
+++ branches/barnowl_unicode/owl/message.c 2008-01-11 19:28:36 UTC (rev 831)
@@ -329,7 +329,7 @@
res=owl_message_get_attribute_value(m, "isprivate");
if (!res) return(0);
- return(1);
+ return !strcmp(res, "true");
}
char *owl_message_get_timestr(owl_message *m)
Modified: branches/barnowl_unicode/owl/perl/lib/BarnOwl/ModuleLoader.pm
===================================================================
--- branches/barnowl_unicode/owl/perl/lib/BarnOwl/ModuleLoader.pm 2008-01-11 06:38:50 UTC (rev 830)
+++ branches/barnowl_unicode/owl/perl/lib/BarnOwl/ModuleLoader.pm 2008-01-11 19:28:36 UTC (rev 831)
@@ -8,6 +8,7 @@
use PAR (BarnOwl::get_config_dir() . "/modules/*.par");
sub load_all {
+ PAR::reload_libs();
my %modules;
my @modules;
@@ -35,7 +36,7 @@
}
for my $class (keys %modules) {
if(!defined eval "use BarnOwl::Module::$class") {
- BarnOwl::error("Unable to load module $class: $!") if $!;
+ # BarnOwl::error("Unable to load module $class: $!") if $!;
BarnOwl::error("Unable to load module $class: $@") if $@;
}
}
@@ -46,7 +47,7 @@
sub register_keybindings {
BarnOwl::new_command('reload-modules', sub {BarnOwl::ModuleLoader->reload}, {
summary => 'Reload all modules',
- usage => 'reload',
+ usage => 'reload-modules',
description => q{Reloads all modules located in ~/.owl/modules and the system modules directory}
});
}
Modified: branches/barnowl_unicode/owl/perl/modules/IRC/lib/BarnOwl/Message/IRC.pm
===================================================================
--- branches/barnowl_unicode/owl/perl/modules/IRC/lib/BarnOwl/Message/IRC.pm 2008-01-11 06:38:50 UTC (rev 830)
+++ branches/barnowl_unicode/owl/perl/modules/IRC/lib/BarnOwl/Message/IRC.pm 2008-01-11 19:28:36 UTC (rev 831)
@@ -55,5 +55,7 @@
sub long_sender {shift->{from} || ""};
+sub login_extra { shift->channel; }
+
1;
Modified: branches/barnowl_unicode/owl/perl/modules/IRC/lib/BarnOwl/Module/IRC/Connection.pm
===================================================================
--- branches/barnowl_unicode/owl/perl/modules/IRC/lib/BarnOwl/Module/IRC/Connection.pm 2008-01-11 06:38:50 UTC (rev 830)
+++ branches/barnowl_unicode/owl/perl/modules/IRC/lib/BarnOwl/Module/IRC/Connection.pm 2008-01-11 19:28:36 UTC (rev 831)
@@ -15,7 +15,7 @@
=cut
use base qw(Net::IRC::Connection Class::Accessor Exporter);
-__PACKAGE__->mk_accessors(qw(alias channels));
+__PACKAGE__->mk_accessors(qw(alias channels motd));
our @EXPORT_OK = qw(&is_private);
use BarnOwl;
@@ -28,13 +28,27 @@
my $self = $class->SUPER::new($irc, %args);
$self->alias($alias);
$self->channels([]);
+ $self->motd("");
bless($self, $class);
- $self->add_global_handler(376 => sub { goto &on_connect });
- $self->add_global_handler(['msg', 'notice', 'public', 'caction'],
+ $self->add_default_handler(sub { goto &on_event; });
+ $self->add_handler(376 => sub { goto &on_connect });
+ $self->add_handler(['msg', 'notice', 'public', 'caction'],
sub { goto &on_msg });
- $self->add_global_handler(cping => sub { goto &on_ping });
- $self->add_default_handler(sub { goto &on_event; });
+ $self->add_handler(['welcome', 'yourhost', 'created',
+ 'luserclient', 'luserop', 'luserchannels', 'luserme'],
+ sub { goto &on_admin_msg });
+ $self->add_handler(['myinfo', 'map', 'n_local', 'n_global',
+ 'luserconns'],
+ sub { });
+ $self->add_handler(motdstart => sub { goto &on_motdstart });
+ $self->add_handler(motd => sub { goto &on_motd });
+ $self->add_handler(endofmotd => sub { goto &on_endofmotd });
+ $self->add_handler(join => sub { goto &on_join });
+ $self->add_handler(part => sub { goto &on_part });
+ $self->add_handler(disconnect => sub { goto &on_disconnect });
+ $self->add_handler(nicknameinuse => sub { goto &on_nickinuse });
+ $self->add_handler(cping => sub { goto &on_ping });
return $self;
}
@@ -48,29 +62,40 @@
BarnOwl::admin_message("IRC", "Connected to " . $self->server . " (" . $self->alias . ")");
}
+sub new_message {
+ my $self = shift;
+ my $evt = shift;
+ return BarnOwl::Message->new(
+ type => 'IRC',
+ server => $self->server,
+ network => $self->alias,
+ sender => $evt->nick,
+ hostname => $evt->host,
+ from => $evt->from,
+ @_
+ );
+}
+
sub on_msg {
my ($self, $evt) = @_;
my ($recipient) = $evt->to;
my $body = strip_irc_formatting([$evt->args]->[0]);
+ my $nick = $self->nick;
+ BarnOwl::beep() if $body =~ /\b\Q$nick\E\b/;
$body = BarnOwl::Style::boldify($evt->nick.' '.$body) if $evt->type eq 'caction';
- my $msg = BarnOwl::Message->new(
- type => 'IRC',
+ my $msg = $self->new_message($evt,
direction => 'in',
- server => $self->server,
- network => $self->alias,
recipient => $recipient,
- body => $body,
- sender => $evt->nick,
- hostname => $evt->host,
- from => $evt->from,
+ body => $body,
$evt->type eq 'notice' ?
(notice => 'true') : (),
is_private($recipient) ?
(isprivate => 'true') : (channel => $recipient),
replycmd => 'irc-msg ' .
(is_private($recipient) ? $evt->nick : $recipient),
- replysendercmd => 'irc-msg ' . $evt->nick,
+ replysendercmd => 'irc-msg ' . $evt->nick
);
+
BarnOwl::queue_message($msg);
}
@@ -79,21 +104,86 @@
$self->ctcp_reply($evt->nick, join (' ', ($evt->args)));
}
+sub on_admin_msg {
+ my ($self, $evt) = @_;
+ BarnOwl::admin_message("IRC",
+ BarnOwl::Style::boldify('IRC ' . $evt->type . ' message from '
+ . $evt->alias) . "\n"
+ . strip_irc_formatting(join '\n', cdr $evt->args));
+}
+
+sub on_motdstart {
+ my ($self, $evt) = @_;
+ $self->motd(join "\n", cdr $evt->args);
+}
+
+sub on_motd {
+ my ($self, $evt) = @_;
+ $self->motd(join "\n", $self->motd, cdr $evt->args);
+}
+
+sub on_endofmotd {
+ my ($self, $evt) = @_;
+ $self->motd(join "\n", $self->motd, cdr $evt->args);
+ BarnOwl::admin_message("IRC",
+ BarnOwl::Style::boldify('MOTD for ' . $evt->alias) . "\n"
+ . strip_irc_formatting($self->motd));
+}
+
+sub on_join {
+ my ($self, $evt) = @_;
+ my $msg = $self->new_message($evt,
+ loginout => 'login',
+ channel => $evt->to,
+ );
+ BarnOwl::queue_message($msg);
+}
+
+sub on_part {
+ my ($self, $evt) = @_;
+ my $msg = $self->new_message($evt,
+ loginout => 'logout',
+ channel => $evt->to,
+ );
+ BarnOwl::queue_message($msg);
+}
+
+sub on_disconnect {
+ my $self = shift;
+ delete $BarnOwl::Module::IRC::ircnets{$self->alias};
+
+ BarnOwl::admin_message('IRC',
+ "[" . $self->alias . "] Disconnected from server");
+}
+
+sub on_nickinuse {
+ my ($self, $evt) = @_;
+ BarnOwl::admin_message("IRC",
+ "[" . $self->alias . "] " .
+ [$evt->args]->[1] . ": Nick already in use");
+}
+
sub on_event {
my ($self, $evt) = @_;
BarnOwl::admin_message("IRC",
- "Unhandled IRC event of type " . $evt->type . ":\n"
+ "[" . $self->alias . "] Unhandled IRC event of type " . $evt->type . ":\n"
. strip_irc_formatting(join("\n", $evt->args)))
if BarnOwl::getvar('irc:spew') eq 'on';
}
+
################################################################################
########################### Utilities/Helpers ##################################
################################################################################
sub strip_irc_formatting {
my $body = shift;
- my @pieces = split /\x02/, $body;
+ # Strip mIRC colors. If someone wants to write code to convert
+ # these to zephyr colors, be my guest.
+ $body =~ s/\cC\d+(?:,\d+)?//g;
+ $body =~ s/\cO//g;
+
+ my @pieces = split /\cB/, $body;
my $out;
while(@pieces) {
$out .= shift @pieces;
@@ -108,4 +198,9 @@
return shift !~ /^[\#\&]/;
}
+sub cdr {
+ shift;
+ return @_;
+}
+
1;
Modified: branches/barnowl_unicode/owl/perl/modules/IRC/lib/BarnOwl/Module/IRC.pm
===================================================================
--- branches/barnowl_unicode/owl/perl/modules/IRC/lib/BarnOwl/Module/IRC.pm 2008-01-11 06:38:50 UTC (rev 830)
+++ branches/barnowl_unicode/owl/perl/modules/IRC/lib/BarnOwl/Module/IRC.pm 2008-01-11 19:28:36 UTC (rev 831)
@@ -29,10 +29,33 @@
our %ircnets;
sub startup {
- BarnOwl::new_variable_string('irc:nick', {default => $ENV{USER}});
- BarnOwl::new_variable_string('irc:user', {default => $ENV{USER}});
- BarnOwl::new_variable_string('irc:name', {default => ""});
- BarnOwl::new_variable_bool('irc:spew', {default => 0});
+ BarnOwl::new_variable_string('irc:nick', {
+ default => $ENV{USER},
+ summary => 'The default IRC nickname',
+ description => 'By default, irc-connect will use this nick ' .
+ 'when connecting to a new server. See :help irc-connect for ' .
+ 'more information.'
+ });
+
+ BarnOwl::new_variable_string('irc:user', {
+ default => $ENV{USER},
+ summary => 'The IRC "username" field'
+ });
+ BarnOwl::new_variable_string('irc:name', {
+ default => "",
+ summary => 'A short name field for IRC',
+ description => 'A short (maybe 60 or so chars) piece of text, ' .
+ 'originally intended to display your real name, which people ' .
+ 'often use for pithy quotes and URLs.'
+ });
+
+ BarnOwl::new_variable_bool('irc:spew', {
+ default => 0,
+ summary => 'Show unhandled IRC events',
+ description => 'If set, display all unrecognized IRC events as ' .
+ 'admin messages. Intended for debugging and development use only '
+ });
+
register_commands();
register_handlers();
BarnOwl::filter('irc type ^IRC$');
@@ -60,11 +83,25 @@
}
sub register_commands {
- BarnOwl::new_command('irc-connect' => \&cmd_connect);
+ BarnOwl::new_command('irc-connect' => \&cmd_connect,
+ {
+ summary => 'Connect to an IRC server',
+ usage => 'irc-connect [-a ALIAS ] [-s] [-p PASSWORD] [-n NICK] SERVER [port]',
+ description =>
+
+ "Connect to an IRC server. Supported options are\n\n" .
+ "-a <alias> Define an alias for this server\n" .
+ "-s Use SSL\n" .
+ "-p <password> Specify the password to use\n" .
+ "-n <nick> Use a non-default nick"
+ });
BarnOwl::new_command('irc-disconnect' => \&cmd_disconnect);
- BarnOwl::new_command('irc-msg' => \&cmd_msg);
- BarnOwl::new_command('irc-join' => \&cmd_join);
- BarnOwl::new_command('irc-nick' => \&cmd_nick);
+ BarnOwl::new_command('irc-msg' => \&cmd_msg);
+ BarnOwl::new_command('irc-join' => \&cmd_join);
+ BarnOwl::new_command('irc-part' => \&cmd_part);
+ BarnOwl::new_command('irc-nick' => \&cmd_nick);
+ BarnOwl::new_command('irc-names' => \&cmd_names);
+ BarnOwl::new_command('irc-whois' => \&cmd_whois);
}
$BarnOwl::Hooks::startup->add(\&startup);
@@ -93,17 +130,24 @@
"alias=s" => \$alias,
"ssl" => \$ssl,
"password=s" => \$password,
- "port=i" => \$port,
+ "nick=s" => \$nick,
);
$host = shift @ARGV or die("Usage: $cmd HOST\n");
if(!$alias) {
- $alias = $1 if $host =~ /^(?:irc[.])?(\w+)[.]\w+$/;
- $alias ||= $host;
+ if($host =~ /^(?:irc[.])?(\w+)[.]\w+$/) {
+ $alias = $1;
+ } else {
+ $alias = $host;
+ }
}
- $port ||= 6667;
+ $port = shift @ARGV || 6667;
$ssl ||= 0;
}
+ if(exists $ircnets{$alias}) {
+ die("Already connected to a server with alias '$alias'. Either disconnect or specify an alias with -a.\n");
+ }
+
my $conn = BarnOwl::Module::IRC::Connection->new($irc, $alias,
Nick => $nick,
Server => $host,
@@ -147,7 +191,7 @@
$conn->privmsg($to, $body);
my $msg = BarnOwl::Message->new(
type => 'IRC',
- direction => 'out',
+ direction => is_private($to) ? 'out' : 'in',
server => $conn->server,
network => $conn->alias,
recipient => $to,
@@ -168,13 +212,34 @@
$conn->join($chan);
}
+sub cmd_part {
+ my $cmd = shift;
+ my $conn = get_connection(\@_);
+ my $chan = get_channel(\@_) || die("Usage: $cmd <channel>\n");
+ $conn->part($chan);
+}
+
sub cmd_nick {
my $cmd = shift;
my $conn = get_connection(\@_);
- my $nick = shift or die("Usage: $cmd <new nick>");
+ my $nick = shift or die("Usage: $cmd <new nick>\n");
$conn->nick($nick);
}
+sub cmd_names {
+ my $cmd = shift;
+ my $conn = get_connection(\@_);
+ my $chan = get_channel(\@_) || die("Usage: $cmd <channel>\n");
+ $conn->names($chan);
+}
+
+sub cmd_whois {
+ my $cmd = shift;
+ my $conn = get_connection(\@_);
+ my $who = shift || die("Usage: $cmd <user>\n");
+ $conn->whois($who);
+}
+
################################################################################
########################### Utilities/Helpers ##################################
################################################################################
@@ -195,6 +260,18 @@
die("You must specify a network with -a\n");
}
+sub get_channel {
+ my $args = shift;
+ if(scalar @$args) {
+ return shift @$args;
+ }
+ my $m = BarnOwl::getcurmsg();
+ if($m && $m->type eq 'IRC') {
+ return $m->channel if !$m->is_private;
+ }
+ return undef;
+}
+
sub get_connection_by_alias {
my $key = shift;
die("No such ircnet: $key\n") unless exists $ircnets{$key};
Modified: branches/barnowl_unicode/owl/perlglue.xs
===================================================================
--- branches/barnowl_unicode/owl/perlglue.xs 2008-01-11 06:38:50 UTC (rev 830)
+++ branches/barnowl_unicode/owl/perlglue.xs 2008-01-11 19:28:36 UTC (rev 831)
@@ -12,8 +12,25 @@
#define SV_IS_CODEREF(sv) (SvROK((sv)) && SvTYPE(SvRV((sv))) == SVt_PVCV)
-MODULE = BarnOwl PACKAGE = BarnOwl
+ /*************************************************************
+ * NOTE
+ *************************************************************
+ * These functions, when they are intended to be user-visible,
+ * are document in perlwrap.pm. If you add functions to this
+ * file, add the appropriate documentation there!
+ *
+ * If the function is simple enough, we simply define its
+ * entire functionality here in XS. If, however, it needs
+ * complex argument processing or something, we define a
+ * simple version here that takes arguments in as flat a
+ * manner as possible, to simplify the XS code, with a name
+ * with a trailing `_internal', and write a perl wrapper in
+ * perlwrap.pm that munges the arguments as appropriate and
+ * calls the internal version.
+ */
+MODULE = BarnOwl PACKAGE = BarnOwl
+
char *
command(cmd)
char *cmd
Modified: branches/barnowl_unicode/owl/perlwrap.pm
===================================================================
--- branches/barnowl_unicode/owl/perlwrap.pm 2008-01-11 06:38:50 UTC (rev 830)
+++ branches/barnowl_unicode/owl/perlwrap.pm 2008-01-11 19:28:36 UTC (rev 831)
@@ -14,6 +14,117 @@
package BarnOwl;
+=head1 NAME
+
+BarnOwl
+
+=head1 DESCRIPTION
+
+The BarnOwl module contains the core of BarnOwl's perl
+bindings. Source in this module is also run at startup to bootstrap
+barnowl by defining things like the default style.
+
+=for NOTE
+These following functions are defined in perlglue.xs. Keep the
+documentation here in sync with the user-visible commands defined
+there!
+
+=head2 command STRING
+
+Executes a BarnOwl command in the same manner as if the user had
+executed it at the BarnOwl command prompt. If the command returns a
+value, return it as a string, otherwise return undef.
+
+=head2 getcurmsg
+
+Returns the current message as a C<BarnOwl::Message> subclass, or
+undef if there is no message selected
+
+=head2 getnumcols
+
+Returns the width of the display window BarnOwl is currently using
+
+=head2 getidletime
+
+Returns the length of time since the user has pressed a key, in
+seconds.
+
+=head2 zephyr_getrealm
+
+Returns the zephyr realm barnowl is running in
+
+=head2 zephyr_getsender
+
+Returns the fully-qualified name of the zephyr sender barnowl is
+running as, e.g. C<nelhage@ATHENA.MIT.EDU>
+
+=head2 zephyr_zwrite COMMAND MESSAGE
+
+Sends a zephyr programmatically. C<COMMAND> should be a C<zwrite>
+command line, and C<MESSAGE> is the zephyr body to send.
+
+=head2 ztext_stylestrip STRING
+
+Strips zephyr formatting from a string and returns the result
+
+=head2 queue_message MESSAGE
+
+Enqueue a message in the BarnOwl message list, logging it and
+processing it appropriately. C<MESSAGE> should be an instance of
+BarnOwl::Message or a subclass.
+
+=head2 admin_message HEADER BODY
+
+Display a BarnOwl B<Admin> message, with the given header and body.
+
+=head2 start_question PROMPT CALLBACK
+
+Displays C<PROMPT> on the screen and lets the user enter a line of
+text, and calls C<CALLBACK>, which must be a perl subroutine
+reference, with the text the user entered
+
+=head2 start_password PROMPT CALLBACK
+
+Like C<start_question>, but echoes the user's input as C<*>s when they
+input.
+
+=head2 start_editwin PROMPT CALLBACK
+
+Like C<start_question>, but displays C<PROMPT> on a line of its own
+and opens the editwin. If the user cancels the edit win, C<CALLBACK>
+is not invoked.
+
+=head2 get_data_dir
+
+Returns the BarnOwl system data directory, where system libraries and
+modules are stored
+
+=head2 get_config_dir
+
+Returns the BarnOwl user configuration directory, where user modules
+and configuration are stored (by default, C<$HOME/.owl>)
+
+=head2 popless_text TEXT
+
+Show a popup window containing the given C<TEXT>
+
+=head2 popless_ztext TEXT
+
+Show a popup window containing the provided zephyr-formatted C<TEXT>
+
+=head2 error STRING
+
+Reports an error and log it in `show errors'. Note that in any
+callback or hook called in perl code from BarnOwl, a C<die> will be
+caught and passed to C<error>.
+
+=head2 getnumcolors
+
+Returns the number of colors this BarnOwl is capable of displaying
+
+=cut
+
+
BEGIN {
# bootstrap in C bindings and glue
*owl:: = \*BarnOwl::;
@@ -46,6 +157,26 @@
return &BarnOwl::Hooks::_receive_msg($m);
}
+=head2 AUTOLOAD
+
+BarnOwl.pm has a C<AUTOLOAD> method that translates unused names in
+the BarnOwl:: namespace to a call to BarnOwl::command() with that
+command. Underscores are also translated to C<->s, so you can do
+e.g. C<BarnOwl::start_command()> and it will be translated into
+C<start-command>.
+
+So, if you're looking for functionality that you can't find in the
+perl interface, check C<:show commands> or C<commands.c> in the
+BarnOwl source tree -- there's a good chance it exists as a BarnOwl
+command.
+
+=head3 BUGS
+
+There are horrible quoting issues here. The AUTOLOAD simple joins your
+commands with spaces and passes them unmodified to C<::command>
+
+=cut
+
# make BarnOwl::<command>("foo") be aliases to BarnOwl::command("<command> foo");
sub AUTOLOAD {
our $AUTOLOAD;
@@ -62,8 +193,25 @@
first argument.
ARGS should be a hashref containing any or all of C<summary>,
-C<usage>, or C<description> keys.
+C<usage>, or C<description> keys:
+=over 4
+
+=item summary
+
+A one-line summary of the purpose of the command
+
+=item usage
+
+A one-line usage synopsis, showing available options and syntax
+
+=item description
+
+A longer description of the syntax and semantics of the command,
+explaining usage and options
+
+=back
+
=cut
sub new_command {
@@ -409,17 +557,44 @@
package BarnOwl::Hook;
+=head1 BarnOwl::Hook
+
+=head1 DESCRIPTION
+
+A C<BarnOwl::Hook> represents a list of functions to be triggered on
+some event. C<BarnOwl> exports a default set of these (see
+C<BarnOwl::Hooks>), but can also be created and used by module code.
+
+=head2 new
+
+Creates a new Hook object
+
+=cut
+
sub new {
my $class = shift;
return bless [], $class;
}
+=head2 run [ARGS]
+
+Calls each of the functions registered with this hook with the given
+arguments.
+
+=cut
+
sub run {
my $self = shift;
my @args = @_;
return map {$_->(@args)} @$self;
}
+=head2 add SUBREF
+
+Registers a given subroutine with this hook
+
+=cut
+
sub add {
my $self = shift;
my $func = shift;
@@ -427,6 +602,12 @@
push @$self, $func;
}
+=head2 clear
+
+Remove all functions registered with this hook.
+
+=cut
+
sub clear {
my $self = shift;
@$self = ();
@@ -434,6 +615,56 @@
package BarnOwl::Hooks;
+=head1 BarnOwl::Hooks
+
+=head1 DESCRIPTION
+
+C<BarnOwl::Hooks> exports a set of C<BarnOwl::Hook> objects made
+available by BarnOwl internally.
+
+=head2 USAGE
+
+Modules wishing to respond to events in BarnOwl should register
+functions with these hooks.
+
+=head2 EXPORTS
+
+None by default. Either import the hooks you need explicitly, or refer
+to them with fully-qualified names. Available hooks are:
+
+=over 4
+
+=item $startup
+
+Called on BarnOwl startup, and whenever modules are
+reloaded. Functions registered with the C<$startup> hook get a true
+argument if this is a reload, and false if this is a true startup
+
+=item $shutdown
+
+Called before BarnOwl shutdown
+
+=item $receiveMessage
+
+Called with a C<BarnOwl::Message> object every time BarnOwl appends a
+new message to its message list
+
+=item $mainLoop
+
+Called on B<every pass> through the C<BarnOwl> main loop. Any
+functions with this hook should be very cheap, as they are very
+frequently by the runtime.
+
+=item $getBuddyList
+
+Called to display buddy lists for all protocol handlers. The result
+from every function registered with this hook will be appended and
+displayed in a popup window, with zephyr formatting parsed.
+
+=back
+
+=cut
+
use Exporter;
our @EXPORT_OK = qw($startup $shutdown
@@ -468,6 +699,10 @@
}
}
+# These are the internal hooks called by the barnowl C code, which
+# take care of dispatching to the appropriate perl hooks, and deal
+# with compatibility by calling the old, fixed-name hooks.
+
sub _startup {
_load_owlconf();
Modified: branches/barnowl_unicode/owl/variable.c
===================================================================
--- branches/barnowl_unicode/owl/variable.c 2008-01-11 06:38:50 UTC (rev 830)
+++ branches/barnowl_unicode/owl/variable.c 2008-01-11 19:28:36 UTC (rev 831)
@@ -454,9 +454,11 @@
/**************************************************************************/
int owl_variable_dict_setup(owl_vardict *vd) {
- owl_variable *cur;
+ owl_variable *var, *cur;
if (owl_dict_create(vd)) return(-1);
- for (cur = variables_to_init; cur->name != NULL; cur++) {
+ for (var = variables_to_init; var->name != NULL; var++) {
+ cur = owl_malloc(sizeof(owl_variable));
+ memcpy(cur, var, sizeof(owl_variable));
switch (cur->type) {
case OWL_VARIABLE_OTHER:
cur->set_fn(cur, cur->pval_default);
@@ -519,7 +521,7 @@
void owl_variable_dict_add_variable(owl_vardict * vardict,
owl_variable * var) {
- owl_dict_insert_element(vardict, var->name, (void*)var, NULL);
+ owl_dict_insert_element(vardict, var->name, (void*)var, (void(*)(void*))owl_variable_free);
}
owl_variable * owl_variable_newvar(char *name, char *summary, char * description) {
@@ -531,47 +533,73 @@
return var;
}
+void owl_variable_update(owl_variable *var, char *summary, char *desc) {
+ if(var->summary) owl_free(var->summary);
+ var->summary = owl_strdup(summary);
+ if(var->description) owl_free(var->description);
+ var->description = owl_strdup(desc);
+}
+
void owl_variable_dict_newvar_string(owl_vardict * vd, char *name, char *summ, char * desc, char * initval) {
- owl_variable * var = owl_variable_newvar(name, summ, desc);
- var->type = OWL_VARIABLE_STRING;
- var->pval_default = owl_strdup(initval);
- var->set_fn = owl_variable_string_set_default;
- var->set_fromstring_fn = owl_variable_string_set_fromstring_default;
- var->get_fn = owl_variable_get_default;
- var->get_tostring_fn = owl_variable_string_get_tostring_default;
- var->free_fn = owl_variable_free_default;
- var->set_fn(var, initval);
- owl_variable_dict_add_variable(vd, var);
+ owl_variable *old = owl_variable_get_var(vd, name, OWL_VARIABLE_STRING);
+ if(old) {
+ owl_variable_update(old, summ, desc);
+ if(old->pval_default) owl_free(old->pval_default);
+ old->pval_default = owl_strdup(initval);
+ } else {
+ owl_variable * var = owl_variable_newvar(name, summ, desc);
+ var->type = OWL_VARIABLE_STRING;
+ var->pval_default = owl_strdup(initval);
+ var->set_fn = owl_variable_string_set_default;
+ var->set_fromstring_fn = owl_variable_string_set_fromstring_default;
+ var->get_fn = owl_variable_get_default;
+ var->get_tostring_fn = owl_variable_string_get_tostring_default;
+ var->free_fn = owl_variable_free_default;
+ var->set_fn(var, initval);
+ owl_variable_dict_add_variable(vd, var);
+ }
}
void owl_variable_dict_newvar_int(owl_vardict * vd, char *name, char *summ, char * desc, int initval) {
- owl_variable * var = owl_variable_newvar(name, summ, desc);
- var->type = OWL_VARIABLE_INT;
- var->ival_default = initval;
- var->validate_fn = owl_variable_int_validate_default;
- var->set_fn = owl_variable_int_set_default;
- var->set_fromstring_fn = owl_variable_int_set_fromstring_default;
- var->get_fn = owl_variable_get_default;
- var->get_tostring_fn = owl_variable_int_get_tostring_default;
- var->free_fn = owl_variable_free_default;
- var->val = owl_malloc(sizeof(int));
- var->set_fn(var, &initval);
- owl_variable_dict_add_variable(vd, var);
+ owl_variable *old = owl_variable_get_var(vd, name, OWL_VARIABLE_INT);
+ if(old) {
+ owl_variable_update(old, summ, desc);
+ old->ival_default = initval;
+ } else {
+ owl_variable * var = owl_variable_newvar(name, summ, desc);
+ var->type = OWL_VARIABLE_INT;
+ var->ival_default = initval;
+ var->validate_fn = owl_variable_int_validate_default;
+ var->set_fn = owl_variable_int_set_default;
+ var->set_fromstring_fn = owl_variable_int_set_fromstring_default;
+ var->get_fn = owl_variable_get_default;
+ var->get_tostring_fn = owl_variable_int_get_tostring_default;
+ var->free_fn = owl_variable_free_default;
+ var->val = owl_malloc(sizeof(int));
+ var->set_fn(var, &initval);
+ owl_variable_dict_add_variable(vd, var);
+ }
}
void owl_variable_dict_newvar_bool(owl_vardict * vd, char *name, char *summ, char * desc, int initval) {
- owl_variable * var = owl_variable_newvar(name, summ, desc);
- var->type = OWL_VARIABLE_BOOL;
- var->ival_default = initval;
- var->validate_fn = owl_variable_bool_validate_default;
- var->set_fn = owl_variable_bool_set_default;
- var->set_fromstring_fn = owl_variable_bool_set_fromstring_default;
- var->get_fn = owl_variable_get_default;
- var->get_tostring_fn = owl_variable_bool_get_tostring_default;
- var->free_fn = owl_variable_free_default;
- var->val = owl_malloc(sizeof(int));
- var->set_fn(var, &initval);
- owl_variable_dict_add_variable(vd, var);
+ owl_variable *old = owl_variable_get_var(vd, name, OWL_VARIABLE_BOOL);
+ if(old) {
+ owl_variable_update(old, summ, desc);
+ old->ival_default = initval;
+ } else {
+ owl_variable * var = owl_variable_newvar(name, summ, desc);
+ var->type = OWL_VARIABLE_BOOL;
+ var->ival_default = initval;
+ var->validate_fn = owl_variable_bool_validate_default;
+ var->set_fn = owl_variable_bool_set_default;
+ var->set_fromstring_fn = owl_variable_bool_set_fromstring_default;
+ var->get_fn = owl_variable_get_default;
+ var->get_tostring_fn = owl_variable_bool_get_tostring_default;
+ var->free_fn = owl_variable_free_default;
+ var->val = owl_malloc(sizeof(int));
+ var->set_fn(var, &initval);
+ owl_variable_dict_add_variable(vd, var);
+ }
}
void owl_variable_dict_free(owl_vardict *d) {
@@ -589,6 +617,7 @@
void owl_variable_free(owl_variable *v) {
if (v->free_fn) v->free_fn(v);
+ owl_free(v);
}
@@ -686,12 +715,18 @@
}
}
-/* returns a reference */
-void *owl_variable_get(owl_vardict *d, char *name, int require_type) {
+owl_variable *owl_variable_get_var(owl_vardict *d, char *name, int require_type) {
owl_variable *v;
if (!name) return(NULL);
v = owl_dict_find_element(d, name);
if (v == NULL || !v->get_fn || v->type != require_type) return(NULL);
+ return v;
+}
+
+/* returns a reference */
+void *owl_variable_get(owl_vardict *d, char *name, int require_type) {
+ owl_variable *v = owl_variable_get_var(d, name, require_type);
+ if(v == NULL) return NULL;
return v->get_fn(v);
}
Modified: branches/barnowl_unicode/owl/zephyr.c
===================================================================
--- branches/barnowl_unicode/owl/zephyr.c 2008-01-11 06:38:50 UTC (rev 830)
+++ branches/barnowl_unicode/owl/zephyr.c 2008-01-11 19:28:36 UTC (rev 831)
@@ -600,16 +600,28 @@
owl_function_makemsg("Message sent to -c %s -i %s\n", retnotice->z_class, retnotice->z_class_inst);
}
} else if (!strcmp(retnotice->z_message, ZSRVACK_NOTSENT)) {
- if (strcasecmp(retnotice->z_class, "message")) {
- char buff[1024];
- owl_function_error("No one subscribed to class class %s", retnotice->z_class);
- sprintf(buff, "Could not send message to class %s: no one subscribed.\n", retnotice->z_class);
+ #define BUFFLEN 1024
+ if (retnotice->z_recipient == NULL
+ || *retnotice->z_recipient == NULL
+ || *retnotice->z_recipient == '@') {
+ char buff[BUFFLEN];
+ owl_function_error("No one subscribed to class %s", retnotice->z_class);
+ snprintf(buff, BUFFLEN, "Could not send message to class %s: no one subscribed.\n", retnotice->z_class);
owl_function_adminmsg("", buff);
} else {
- char buff[1024];
+ char buff[BUFFLEN];
tmp = short_zuser(retnotice->z_recipient);
- owl_function_error("%s: Not logged in or subscribing to messages.", tmp);
- sprintf(buff, "Could not send message to %s: not logged in or subscribing to messages.\n", tmp);
+ owl_function_error("%s: Not logged in or subscribing.", tmp);
+ snprintf(buff, BUFFLEN, "Could not send message to %s: not logged in or subscribing to", tmp);
+ if(strcmp(retnotice->z_class, "message")) {
+ snprintf(buff, BUFFLEN,
+ "%s class %s, instance %s.\n", buff,
+ retnotice->z_class,
+ retnotice->z_class_inst);
+ } else {
+ snprintf(buff, BUFFLEN,
+ "%s messages.\n", buff);
+ }
owl_function_adminmsg("", buff);
owl_log_outgoing_zephyr_error(tmp, buff);
owl_free(tmp);