source: perlwrap.pm @ e8bc8ac

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