source: perlwrap.pm @ a695a68

barnowl_perlaimdebianrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since a695a68 was a695a68, checked in by Nelson Elhage <nelhage@mit.edu>, 17 years ago
Adding the ability to define new variables from perl.
  • Property mode set to 100644
File size: 15.5 KB
RevLine 
[f1e629d]1# $Id$
2#
3# This is all linked into the binary and evaluated when perl starts up...
4#
5#####################################################################
6#####################################################################
[b6c067a]7# XXX NOTE: This file is sourced before almost any barnowl
8# architecture is loaded. This means, for example, that it cannot
[0337203]9# execute any owl commands. Any code that needs to do so should live
10# in BarnOwl::Hooks::_startup
[f1e629d]11
[c681337]12use strict;
13use warnings;
14
[8203afd]15package BarnOwl;
[f1e629d]16
[8862725]17BEGIN {
[f1e629d]18# bootstrap in C bindings and glue
[8203afd]19    *owl:: = \*BarnOwl::;
20    bootstrap BarnOwl 1.2;
[8862725]21};
22
[3354cea5]23use lib(get_data_dir()."/lib");
[2e3b9c2]24use lib($ENV{HOME}."/.owl/lib");
[8862725]25
[00f9a7d]26our $configfile;
27
[2e3b9c2]28if(!$configfile && -f $ENV{HOME} . "/.barnowlconf") {
29    $configfile = $ENV{HOME} . "/.barnowlconf";
30}
31$configfile ||= $ENV{HOME}."/.owlconf";
[d03091c]32
[186cdc4]33# populate global variable space for legacy owlconf files
[f1e629d]34sub _format_msg_legacy_wrap {
35    my ($m) = @_;
36    $m->legacy_populate_global();
[8203afd]37    return &BarnOwl::format_msg($m);
[f1e629d]38}
39
[186cdc4]40# populate global variable space for legacy owlconf files
[f1e629d]41sub _receive_msg_legacy_wrap {
42    my ($m) = @_;
43    $m->legacy_populate_global();
[0337203]44    return &BarnOwl::Hooks::_receive_msg($m);
[f1e629d]45}
46
[8203afd]47# make BarnOwl::<command>("foo") be aliases to BarnOwl::command("<command> foo");
[f1e629d]48sub AUTOLOAD {
[c681337]49    our $AUTOLOAD;
[f1e629d]50    my $called = $AUTOLOAD;
51    $called =~ s/.*:://;
[e7ac2b6]52    $called =~ s/_/-/g;
[8203afd]53    return &BarnOwl::command("$called ".join(" ",@_));
[f1e629d]54}
55
[6922edd]56=head2 new_command NAME FUNC [{ARGS}]
57
58Add a new owl command. When owl executes the command NAME, FUNC will
59be called with the arguments passed to the command, with NAME as the
60first argument.
61
62ARGS should be a hashref containing any or all of C<summary>,
63C<usage>, or C<description> keys.
64
65=cut
66
67sub new_command {
68    my $name = shift;
69    my $func = shift;
70    my $args = shift || {};
71    my %args = (
72        summary     => undef,
73        usage       => undef,
74        description => undef,
75        %{$args}
76    );
77
[c681337]78    no warnings 'uninitialized';
[8203afd]79    BarnOwl::new_command_internal($name, $func, $args{summary}, $args{usage}, $args{description});
[6922edd]80}
81
[a695a68]82sub new_variable_int {
83    unshift @_, \&BarnOwl::new_variable_int_internal, 0;
84    goto \&_new_variable;
85}
86
87sub new_variable_bool {
88    unshift @_, \&BarnOwl::new_variable_bool_internal, 0;
89    goto \&_new_variable;
90}
91
92sub new_variable_string {
93    unshift @_, \&BarnOwl::new_variable_string_internal, "";
94    goto \&_new_variable;
95}
96
97sub _new_variable {
98    my $func = shift;
99    my $default_default = shift;
100    my $name = shift;
101    my $args = shift || {};
102    my %args = (
103        summary     => "",
104        description => "",
105        default     => $default_default,
106        %{$args});
107    $func->($name, $args{default}, $args{summary}, $args{description});
108}
109
[f1e629d]110#####################################################################
111#####################################################################
112
[8203afd]113package BarnOwl::Message;
[f1e629d]114
[dd16bdd]115sub new {
116    my $class = shift;
117    my %args = (@_);
118    if($class eq __PACKAGE__ && $args{type}) {
[8203afd]119        $class = "BarnOwl::Message::" . ucfirst $args{type};
[dd16bdd]120    }
121    return bless {%args}, $class;
122}
123
[f1e629d]124sub type        { return shift->{"type"}; }
125sub direction   { return shift->{"direction"}; }
126sub time        { return shift->{"time"}; }
127sub id          { return shift->{"id"}; }
128sub body        { return shift->{"body"}; }
129sub sender      { return shift->{"sender"}; }
130sub recipient   { return shift->{"recipient"}; }
131sub login       { return shift->{"login"}; }
[216c734]132sub is_private  { return shift->{"private"}; }
[f1e629d]133
134sub is_login    { return shift->login eq "login"; }
135sub is_logout   { return shift->login eq "logout"; }
136sub is_loginout { my $m=shift; return ($m->is_login or $m->is_logout); }
137sub is_incoming { return (shift->{"direction"} eq "in"); }
138sub is_outgoing { return (shift->{"direction"} eq "out"); }
139
140sub is_deleted  { return shift->{"deleted"}; }
141
142sub is_admin    { return (shift->{"type"} eq "admin"); }
143sub is_generic  { return (shift->{"type"} eq "generic"); }
[421c8ef7]144sub is_zephyr   { return (shift->{"type"} eq "zephyr"); }
[467aa16]145sub is_aim      { return (shift->{"type"} eq "AIM"); }
[dd16bdd]146sub is_jabber   { return (shift->{"type"} eq "jabber"); }
[421c8ef7]147sub is_icq      { return (shift->{"type"} eq "icq"); }
148sub is_yahoo    { return (shift->{"type"} eq "yahoo"); }
149sub is_msn      { return (shift->{"type"} eq "msn"); }
150sub is_loopback { return (shift->{"type"} eq "loopback"); }
[f1e629d]151
152# These are overridden by appropriate message types
153sub is_ping     { return 0; }
154sub is_mail     { return 0; }
[3c9012b]155sub is_personal { return shift->is_private; }
[f1e629d]156sub class       { return undef; }
157sub instance    { return undef; }
158sub realm       { return undef; }
159sub opcode      { return undef; }
160sub header      { return undef; }
161sub host        { return undef; }
162sub hostname    { return undef; }
163sub auth        { return undef; }
164sub fields      { return undef; }
165sub zsig        { return undef; }
166sub zwriteline  { return undef; }
[87c6ef1]167sub login_host  { return undef; }
168sub login_tty   { return undef; }
[f1e629d]169
[ae47efb]170sub pretty_sender    { return shift->sender; }
171sub pretty_recipient { return shift->recipient; }
[f1e629d]172
173sub delete {
174    my ($m) = @_;
[8203afd]175    &BarnOwl::command("delete --id ".$m->id);
[f1e629d]176}
177
178sub undelete {
179    my ($m) = @_;
[8203afd]180    &BarnOwl::command("undelete --id ".$m->id);
[f1e629d]181}
182
183# Serializes the message into something similar to the zwgc->vt format
184sub serialize {
185    my ($this) = @_;
186    my $s;
187    for my $f (keys %$this) {
188        my $val = $this->{$f};
189        if (ref($val) eq "ARRAY") {
190            for my $i (0..@$val-1) {
191                my $aval;
192                $aval = $val->[$i];
193                $aval =~ s/\n/\n$f.$i: /g;
[186cdc4]194                $s .= "$f.$i: $aval\n";
[f1e629d]195            }
196        } else {
197            $val =~ s/\n/\n$f: /g;
198            $s .= "$f: $val\n";
199        }
200    }
201    return $s;
202}
203
204# Populate the annoying legacy global variables
205sub legacy_populate_global {
206    my ($m) = @_;
[8203afd]207    $BarnOwl::direction  = $m->direction ;
208    $BarnOwl::type       = $m->type      ;
209    $BarnOwl::id         = $m->id        ;
210    $BarnOwl::class      = $m->class     ;
211    $BarnOwl::instance   = $m->instance  ;
212    $BarnOwl::recipient  = $m->recipient ;
213    $BarnOwl::sender     = $m->sender    ;
214    $BarnOwl::realm      = $m->realm     ;
215    $BarnOwl::opcode     = $m->opcode    ;
216    $BarnOwl::zsig       = $m->zsig      ;
217    $BarnOwl::msg        = $m->body      ;
218    $BarnOwl::time       = $m->time      ;
219    $BarnOwl::host       = $m->host      ;
220    $BarnOwl::login      = $m->login     ;
221    $BarnOwl::auth       = $m->auth      ;
[f1e629d]222    if ($m->fields) {
[8203afd]223        @BarnOwl::fields = @{$m->fields};
[f1e629d]224        @main::fields = @{$m->fields};
225    } else {
[8203afd]226        @BarnOwl::fields = undef;
[f1e629d]227        @main::fields = undef;
228    }
229}
230
[25729b2]231sub smartfilter {
[0337203]232    die("smartfilter not supported for this message\n");
[25729b2]233}
234
[6e6ded7]235# Display fields -- overridden by subclasses when needed
236sub login_type {""}
237sub login_extra {""}
238sub long_sender {""}
239
240# The context in which a non-personal message was sent, e.g. a chat or
241# class
242sub context {""}
243
244# Some indicator of context *within* $self->context. e.g. the zephyr
245# instance
246sub subcontext {""}
247
[f1e629d]248#####################################################################
249#####################################################################
250
[8203afd]251package BarnOwl::Message::Admin;
[f1e629d]252
[8203afd]253use base qw( BarnOwl::Message );
[f1e629d]254
255sub header       { return shift->{"header"}; }
256
257#####################################################################
258#####################################################################
259
[8203afd]260package BarnOwl::Message::Generic;
[f1e629d]261
[8203afd]262use base qw( BarnOwl::Message );
[f1e629d]263
264#####################################################################
265#####################################################################
266
[186cdc4]267package BarnOwl::Message::Loopback;
268
269use base qw( BarnOwl::Message );
270
[cb06a43]271# all loopback messages are private
272sub is_private {
[186cdc4]273  return 1;
274}
275
276#####################################################################
277#####################################################################
278
[8203afd]279package BarnOwl::Message::AIM;
[f1e629d]280
[8203afd]281use base qw( BarnOwl::Message );
[f1e629d]282
[cb06a43]283# all non-loginout AIM messages are private for now...
284sub is_private {
[f1e629d]285    return !(shift->is_loginout);
286}
287
288#####################################################################
289#####################################################################
290
[8203afd]291package BarnOwl::Message::Zephyr;
[f1e629d]292
[8203afd]293use base qw( BarnOwl::Message );
[f1e629d]294
[6e6ded7]295sub login_type {
296    return (shift->zsig eq "") ? "(PSEUDO)" : "";
297}
298
299sub login_extra {
300    my $m = shift;
301    return undef if (!$m->is_loginout);
302    my $s = lc($m->host);
303    $s .= " " . $m->login_tty if defined $m->login_tty;
304    return $s;
305}
306
307sub long_sender {
308    my $m = shift;
309    return $m->zsig;
310}
311
312sub context {
313    return shift->class;
314}
315
316sub subcontext {
317    return shift->instance;
318}
319
[186cdc4]320sub login_tty {
[f1e629d]321    my ($m) = @_;
322    return undef if (!$m->is_loginout);
323    return $m->fields->[2];
324}
325
[186cdc4]326sub login_host {
[f1e629d]327    my ($m) = @_;
328    return undef if (!$m->is_loginout);
329    return $m->fields->[0];
330}
331
332sub zwriteline  { return shift->{"zwriteline"}; }
333
334sub is_ping     { return (lc(shift->opcode) eq "ping"); }
335
[186cdc4]336sub is_personal {
[f1e629d]337    my ($m) = @_;
338    return ((lc($m->class) eq "message")
339            && (lc($m->instance) eq "personal")
340            && $m->is_private);
341}
342
[186cdc4]343sub is_mail {
[f1e629d]344    my ($m) = @_;
345    return ((lc($m->class) eq "mail") && $m->is_private);
346}
347
348sub pretty_sender {
349    my ($m) = @_;
350    my $sender = $m->sender;
[8203afd]351    my $realm = BarnOwl::zephyr_getrealm();
[f1e629d]352    $sender =~ s/\@$realm$//;
353    return $sender;
354}
355
[ae47efb]356sub pretty_recipient {
357    my ($m) = @_;
358    my $recip = $m->recipient;
359    my $realm = BarnOwl::zephyr_getrealm();
360    $recip =~ s/\@$realm$//;
361    return $recip;
362}
363
[f1e629d]364# These are arguably zephyr-specific
365sub class       { return shift->{"class"}; }
366sub instance    { return shift->{"instance"}; }
367sub realm       { return shift->{"realm"}; }
368sub opcode      { return shift->{"opcode"}; }
369sub host        { return shift->{"hostname"}; }
370sub hostname    { return shift->{"hostname"}; }
371sub header      { return shift->{"header"}; }
372sub auth        { return shift->{"auth"}; }
373sub fields      { return shift->{"fields"}; }
374sub zsig        { return shift->{"zsig"}; }
375
376#####################################################################
377#####################################################################
[7e470da]378################################################################################
379
[0337203]380package BarnOwl::Hook;
[7e470da]381
[0337203]382sub new {
383    my $class = shift;
384    return bless [], $class;
385}
[7e470da]386
[0337203]387sub run {
388    my $self = shift;
389    my @args = @_;
390    return map {$_->(@args)} @$self;
[7e470da]391}
[0337203]392
393sub add {
394    my $self = shift;
395    my $func = shift;
396    die("Not a coderef!") unless ref($func) eq 'CODE';
397    push @$self, $func;
[7e470da]398}
399
[0337203]400sub clear {
401    my $self = shift;
402    @$self = ();
[7e470da]403}
404
[0337203]405package BarnOwl::Hooks;
[7e470da]406
[0337203]407use Exporter;
408
409our @EXPORT_OK = qw($startup $shutdown
410                    $receiveMessage $mainLoop
411                    $getBuddyList);
412
413our %EXPORT_TAGS = (all => [@EXPORT_OK]);
414
415our $startup = BarnOwl::Hook->new;
416our $shutdown = BarnOwl::Hook->new;
417our $receiveMessage = BarnOwl::Hook->new;
418our $mainLoop = BarnOwl::Hook->new;
419our $getBuddyList = BarnOwl::Hook->new;
420
421# Internal startup/shutdown routines called by the C code
[7e470da]422
[b6c067a]423sub _load_owlconf {
424    # load the config  file
425    if ( -r $BarnOwl::configfile ) {
426        undef $@;
[e8bc8ac]427        package main;
[b6c067a]428        do $BarnOwl::configfile;
429        die $@ if $@;
[e8bc8ac]430        package BarnOwl;
[39dc159]431        if(*BarnOwl::format_msg{CODE}) {
432            # if the config defines a legacy formatting function, add 'perl' as a style
433            BarnOwl::_create_style("perl", "BarnOwl::_format_msg_legacy_wrap",
434                                   "User-defined perl style that calls BarnOwl::format_msg"
435                                   . " with legacy global variable support");
436            BarnOwl::set("-q default_style perl");
437        }
[b6c067a]438    }
439}
440
[0337203]441sub _startup {
442    _load_owlconf();
[8203afd]443
[0337203]444    if(eval {require BarnOwl::ModuleLoader}) {
445        eval {
446            BarnOwl::ModuleLoader->load_all;
447        };
[f6b319c]448        BarnOwl::error("$@") if $@;
449open TMP, ">/tmp/error";
450print TMP $@;
451
[0337203]452    } else {
453        BarnOwl::error("Can't load BarnOwl::ModuleLoader, loadable module support disabled:\n$@");
454    }
455   
[836e6263]456    $startup->run(0);
[8203afd]457    BarnOwl::startup() if *BarnOwl::startup{CODE};
458}
459
[0337203]460sub _shutdown {
461    $shutdown->run;
462   
[8203afd]463    BarnOwl::shutdown() if *BarnOwl::shutdown{CODE};
464}
465
[0337203]466sub _receive_msg {
[7e470da]467    my $m = shift;
[0337203]468
469    $receiveMessage->run($m);
470   
[8203afd]471    BarnOwl::receive_msg($m) if *BarnOwl::receive_msg{CODE};
[7e470da]472}
473
[0337203]474sub _mainloop_hook {
475    $mainLoop->run;
476    BarnOwl::mainloop_hook() if *BarnOwl::mainloop_hook{CODE};
477}
[7e470da]478
[0337203]479sub _get_blist {
480    return join("\n", $getBuddyList->run);
[7e470da]481}
[dd16bdd]482
[b6c067a]483################################################################################
484# Built-in perl styles
485################################################################################
486package BarnOwl::Style::Default;
487################################################################################
488# Branching point for various formatting functions in this style.
489################################################################################
490sub format_message($)
491{
492    my $m = shift;
493
[6e6ded7]494    if ( $m->is_loginout) {
495        return format_login($m);
496    } elsif($m->is_ping) {
497        return ( "\@b(PING) from \@b(" . $m->pretty_sender . ")\n" );
498    } elsif($m->is_admin) {
[b6c067a]499        return "\@bold(OWL ADMIN)\n" . indentBody($m);
[6e6ded7]500    } else {
501        return format_chat($m);
[b6c067a]502    }
503}
504
505BarnOwl::_create_style("default", "BarnOwl::Style::Default::format_message", "Default style");
506
507################################################################################
508
[6e6ded7]509sub time_hhmm {
510    my $m = shift;
[b6c067a]511    my ($time) = $m->time =~ /(\d\d:\d\d)/;
[6e6ded7]512    return $time;
[b6c067a]513}
514
[6e6ded7]515sub format_login($) {
[b6c067a]516    my $m = shift;
[6e6ded7]517    return sprintf(
518        '@b<%s%s> for @b(%s) (%s) %s',
519        uc( $m->login ),
520        $m->login_type,
521        $m->pretty_sender,
522        $m->login_extra,
523        time_hhmm($m)
524       );
[b6c067a]525}
526
[6e6ded7]527sub format_chat($) {
[b6c067a]528    my $m = shift;
[6e6ded7]529    my $header;
530    if ( $m->is_personal ) {
531        if ( $m->direction eq "out" ) {
532            $header = ucfirst $m->type . " sent to " . $m->pretty_recipient;
533        } else {
534            $header = ucfirst $m->type . " from " . $m->pretty_sender;
535        }
536    } else {
537        $header = $m->context;
[37dd88c]538        if(defined $m->subcontext) {
[c39999f]539            $header .= ' / ' . $m->subcontext;
[6e6ded7]540        }
[c39999f]541        $header .= ' / @b{' . $m->pretty_sender . '}';
[6e6ded7]542    }
[b6c067a]543
[6e6ded7]544    $header .= "  " . time_hhmm($m);
[0449730]545    my $sender = $m->long_sender;
546    $sender =~ s/\n.*$//s;
[cc5b906]547    $header .= " " x (4 - ((length $header) % 4));
548    $header .= "(" . $sender . ")";
[6e6ded7]549    my $message = $header . "\n". indentBody($m);
[cb06a43]550    if($m->is_personal && $m->direction eq "in") {
[6e6ded7]551        $message = BarnOwl::Style::boldify($message);
552    }
553    return $message;
[b6c067a]554}
555
556sub indentBody($)
557{
558    my $m = shift;
[186cdc4]559
[b6c067a]560    my $body = $m->body;
[f6b319c]561    if ($m->{should_wordwrap}) {
562      $body = BarnOwl::wordwrap($body, BarnOwl::getnumcols()-8);
563    }
[186cdc4]564    # replace newline followed by anything with
[b6c067a]565    # newline plus four spaces and that thing.
566    $body =~ s/\n(.)/\n    $1/g;
567
568    return "    ".$body;
569}
570
571
572package BarnOwl::Style;
573
574# This takes a zephyr to be displayed and modifies it to be displayed
575# entirely in bold.
576sub boldify($)
577{
578    local $_ = shift;
579    if ( !(/\)/) ) {
580        return '@b(' . $_ . ')';
581    } elsif ( !(/\>/) ) {
582        return '@b<' . $_ . '>';
583    } elsif ( !(/\}/) ) {
584        return '@b{' . $_ . '}';
585    } elsif ( !(/\]/) ) {
586        return '@b[' . $_ . ']';
587    } else {
588        my $txt = "\@b($_";
589        $txt =~ s/\)/\)\@b\[\)\]\@b\(/g;
590        return $txt . ')';
591    }
592}
593
594
[f1e629d]595# switch to package main when we're done
596package main;
[0337203]597
598# Shove a bunch of fake entries into @INC so modules can use or
599# require them without choking
600$::INC{$_} = 1 for (qw(BarnOwl.pm BarnOwl/Hooks.pm
601                       BarnOwl/Message.pm BarnOwl/Style.pm));
[f1e629d]602
6031;
[0337203]604
Note: See TracBrowser for help on using the repository browser.