[839] in BarnOwl Developers

home help back first fref pref prev next nref lref last post

[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);


home help back first fref pref prev next nref lref last post