Changeset 5832433


Ignore:
Timestamp:
Aug 8, 2013, 5:00:24 PM (8 years ago)
Author:
David Benjamin <davidben@mit.edu>
Parents:
ecd4edf (diff), f421190 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:
Merge f42119083e54d646257d2fc7bbb29314a62fe4bb into ecd4edf8785a764941194e565a5129ce1bce8bee
Files:
9 added
50 deleted
54 edited
1 moved

Legend:

Unmodified
Added
Removed
  • perl/modules/Jabber/lib/BarnOwl/Module/Jabber.pm

    r8258ea5 r5832433  
    1616use BarnOwl;
    1717use BarnOwl::Hooks;
    18 use BarnOwl::Message::Jabber;
    19 use BarnOwl::Module::Jabber::Connection;
    20 use BarnOwl::Module::Jabber::ConnectionManager;
    21 use BarnOwl::Completion::Util qw(complete_flags);
    22 
    23 use Authen::SASL qw(Perl);
    24 use Net::Jabber;
    25 use Net::Jabber::MUC;
    26 use Net::DNS;
    27 use Getopt::Long;
    28 Getopt::Long::Configure(qw(no_getopt_compat prefix_pattern=-|--));
    2918
    3019use utf8;
     
    3221our $VERSION = 0.1;
    3322
    34 BEGIN {
    35     if(eval {require IO::Socket::SSL;}) {
    36         if($IO::Socket::SSL::VERSION eq "0.97") {
    37             BarnOwl::error("You are using IO::Socket:SSL 0.97, which \n" .
    38                            "contains bugs causing it not to work with BarnOwl's\n" .
    39                            "Jabber support. We recommend updating to the latest\n" .
    40                            "IO::Socket::SSL from CPAN. \n");
    41             die("Not loading Jabber.par\n");
    42         }
     23our $impl_loaded;
     24$impl_loaded = 0 unless defined($impl_loaded);
     25
     26sub _load_impl {
     27    unless ($impl_loaded) {
     28        BarnOwl::debug("_load_impl");
     29        require BarnOwl::Module::Jabber::Impl;
     30        $impl_loaded = 1;
     31        BarnOwl::Module::Jabber::Impl::onStart();
    4332    }
    4433}
    45 
    46 no warnings 'redefine';
    47 
    48 ################################################################################
    49 # owl perl jabber support
    50 #
    51 # XXX Todo:
    52 # Rosters for MUCs
    53 # More user feedback
    54 #  * joining MUC
    55 #  * parting MUC
    56 #  * presence (Roster and MUC)
    57 # Implementing formatting and logging callbacks for C
    58 # Appropriate callbacks for presence subscription messages.
    59 #
    60 ################################################################################
    61 
    62 our $conn;
    63 $conn ||= BarnOwl::Module::Jabber::ConnectionManager->new;
    64 our %vars;
    65 our %completion_jids;
    6634
    6735sub onStart {
     
    7038        register_keybindings();
    7139        register_filters();
    72         $BarnOwl::Hooks::getBuddyList->add("BarnOwl::Module::Jabber::onGetBuddyList");
    7340        $BarnOwl::Hooks::getQuickstart->add("BarnOwl::Module::Jabber::onGetQuickstart");
    74         $vars{show} = '';
     41
    7542        BarnOwl::new_variable_bool("jabber:show_offline_buddies",
    7643                                   { default => 1,
     
    9461                                    summary => 'Auto-reconnect when disconnected from servers.'
    9562                                });
    96         # Force these. Reload can screw them up.
    97         # Taken from Net::Jabber::Protocol.
    98         $Net::XMPP::Protocol::NEWOBJECT{'iq'}       = "Net::Jabber::IQ";
    99         $Net::XMPP::Protocol::NEWOBJECT{'message'}  = "Net::Jabber::Message";
    100         $Net::XMPP::Protocol::NEWOBJECT{'presence'} = "Net::Jabber::Presence";
    101         $Net::XMPP::Protocol::NEWOBJECT{'jid'}      = "Net::Jabber::JID";
     63
     64        # If we're called as part of module reload, let Impl's reload
     65        # code run too.
     66        if ($impl_loaded) {
     67            BarnOwl::Module::Jabber::Impl::onStart();
     68        }
    10269    } else {
    10370        # Our owl doesn't support queue_message. Unfortunately, this
     
    10976$BarnOwl::Hooks::startup->add("BarnOwl::Module::Jabber::onStart");
    11077
    111 sub do_keep_alive_and_auto_away {
    112     if ( !$conn->connected() ) {
    113         # We don't need this timer any more.
    114         if (defined $vars{keepAliveTimer}) {
    115             $vars{keepAliveTimer}->stop;
    116         }
    117         delete $vars{keepAliveTimer};
    118         return;
    119     }
    120 
    121     $vars{status_changed} = 0;
    122     my $auto_away = BarnOwl::getvar('jabber:auto_away_timeout');
    123     my $auto_xa = BarnOwl::getvar('jabber:auto_xa_timeout');
    124     my $idletime = BarnOwl::getidletime();
    125     if ($auto_xa != 0 && $idletime >= (60 * $auto_xa) && ($vars{show} eq 'away' || $vars{show} eq '' )) {
    126         $vars{show} = 'xa';
    127         $vars{status} = 'Auto extended-away after '.$auto_xa.' minute'.($auto_xa == 1 ? '' : 's').' idle.';
    128         $vars{status_changed} = 1;
    129     } elsif ($auto_away != 0 && $idletime >= (60 * $auto_away) && $vars{show} eq '') {
    130         $vars{show} = 'away';
    131         $vars{status} = 'Auto away after '.$auto_away.' minute'.($auto_away == 1 ? '' : 's').' idle.';
    132         $vars{status_changed} = 1;
    133     } elsif ($idletime <= $vars{idletime} && $vars{show} ne '') {
    134         $vars{show} = '';
    135         $vars{status} = '';
    136         $vars{status_changed} = 1;
    137     }
    138     $vars{idletime} = $idletime;
    139 
    140     foreach my $jid ( $conn->getJIDs() ) {
    141         next if $conn->jidActive($jid);
    142         $conn->tryReconnect($jid);
    143     }
    144 
    145     foreach my $jid ( $conn->getJIDs() ) {
    146         next unless $conn->jidActive($jid);
    147 
    148         my $client = $conn->getConnectionFromJID($jid);
    149         unless($client) {
    150             $conn->removeConnection($jid);
    151             BarnOwl::error("Connection for $jid undefined -- error in reload?");
    152         }
    153         my $status = $client->Process(0); # keep-alive
    154         if ( !defined($status) ) {
    155             $conn->scheduleReconnect($jid);
    156         }
    157         if ($::shutdown) {
    158             do_logout($jid);
    159             next;
    160         }
    161 
    162         if ($vars{status_changed}) {
    163             my $p = new Net::Jabber::Presence;
    164             $p->SetShow($vars{show}) if $vars{show};
    165             $p->SetStatus($vars{status}) if $vars{status};
    166             $client->Send($p);
    167         }
     78sub _make_stub {
     79    my $func = shift;
     80    return sub {
     81        _load_impl();
     82        no strict 'refs';
     83        &{"BarnOwl::Module::Jabber::Impl::$func"};
    16884    }
    16985}
    17086
    171 our $showOffline = 0;
    172 
    173 sub blist_listBuddy {
    174     my $roster = shift;
    175     my $buddy  = shift;
    176     my $blistStr .= "    ";
    177     my %jq  = $roster->query($buddy);
    178     my $res = $roster->resource($buddy);
    179 
    180     my $name = $jq{name} || $buddy->GetUserID();
    181 
    182     $blistStr .= sprintf '%-15s %s', $name, $buddy->GetJID();
    183     $completion_jids{$name} = 1;
    184     $completion_jids{$buddy->GetJID()} = 1;
    185 
    186     if ($res) {
    187         my %rq = $roster->resourceQuery( $buddy, $res );
    188         $blistStr .= " [" . ( $rq{show} ? $rq{show} : 'online' ) . "]";
    189         $blistStr .= " " . $rq{status} if $rq{status};
    190         $blistStr = BarnOwl::Style::boldify($blistStr) if $showOffline;
    191     }
    192     else {
    193         return '' unless $showOffline;
    194         if ($jq{ask}) {
    195             $blistStr .= " [pending]";
    196         }
    197         elsif ($jq{subscription} eq 'none' || $jq{subscription} eq 'from') {
    198             $blistStr .= " [not subscribed]";
    199         }
    200         else {
    201             $blistStr .= " [offline]";
    202         }
    203     }
    204     return $blistStr . "\n";
    205 }
    206 
    207 # Sort, ignoring markup.
    208 sub blistSort {
    209     return uc(BarnOwl::ztext_stylestrip($a)) cmp uc(BarnOwl::ztext_stylestrip($b));
    210 }
    211 
    212 sub getSingleBuddyList {
    213     my $jid = shift;
    214     $jid = resolveConnectedJID($jid);
    215     return "" unless $jid;
    216     my $blist = "";
    217     my $roster = $conn->getRosterFromJID($jid);
    218     if ($roster) {
    219         $blist .= BarnOwl::Style::boldify("Jabber roster for $jid\n");
    220 
    221         my @gTexts = ();
    222         foreach my $group ( $roster->groups() ) {
    223             my @buddies = $roster->jids( 'group', $group );
    224             my @bTexts = ();
    225             foreach my $buddy ( @buddies ) {
    226                 push(@bTexts, blist_listBuddy( $roster, $buddy ));
    227             }
    228             push(@gTexts, "  Group: $group\n".join('',sort blistSort @bTexts));
    229         }
    230         # Sort groups before adding ungrouped entries.
    231         @gTexts = sort blistSort @gTexts;
    232 
    233         my @unsorted = $roster->jids('nogroup');
    234         if (@unsorted) {
    235             my @bTexts = ();
    236             foreach my $buddy (@unsorted) {
    237                 push(@bTexts, blist_listBuddy( $roster, $buddy ));
    238             }
    239             push(@gTexts, "  [unsorted]\n".join('',sort blistSort @bTexts));
    240         }
    241         $blist .= join('', @gTexts);
    242     }
    243     return $blist;
    244 }
    245 
    246 sub onGetBuddyList {
    247     $showOffline = BarnOwl::getvar('jabber:show_offline_buddies') eq 'on';
    248     my $blist = "";
    249     foreach my $jid ($conn->getJIDs()) {
    250         $blist .= getSingleBuddyList($jid);
    251     }
    252     return $blist;
    253 }
    254 
    255 sub onGetQuickstart {
    256     return <<'EOF'
    257 @b(Jabber:)
    258 Type ':jabberlogin @b(username@mit.edu)' to log in to Jabber. The command
    259 ':jroster sub @b(somebody@gmail.com)' will request that they let you message
    260 them. Once you get a message saying you are subscribed, you can message
    261 them by typing ':jwrite @b(somebody@gmail.com)' or just 'j @b(somebody)'.
    262 EOF
    263 }
    264 
    265 ################################################################################
    266 ### Owl Commands
    26787sub register_owl_commands() {
    26888    BarnOwl::new_command(
    269         jabberlogin => \&cmd_login,
     89        jabberlogin => _make_stub("cmd_login"),
    27090        {
    27191            summary => "Log in to Jabber",
     
    27494    );
    27595    BarnOwl::new_command(
    276         jabberlogout => \&cmd_logout,
     96        jabberlogout => _make_stub("cmd_logout"),
    27797        {
    27898            summary => "Log out of Jabber",
     
    285105    );
    286106    BarnOwl::new_command(
    287         jwrite => \&cmd_jwrite,
     107        jwrite => _make_stub("cmd_jwrite"),
    288108        {
    289109            summary => "Send a Jabber Message",
     
    292112    );
    293113    BarnOwl::new_command(
    294         jaway => \&cmd_jaway,
     114        jaway => _make_stub("cmd_jaway"),
    295115        {
    296116            summary => "Set Jabber away / presence information",
     
    299119    );
    300120    BarnOwl::new_command(
    301         jlist => \&cmd_jlist,
     121        jlist => _make_stub("cmd_jlist"),
    302122        {
    303123            summary => "Show your Jabber roster.",
     
    306126    );
    307127    BarnOwl::new_command(
    308         jmuc => \&cmd_jmuc,
     128        jmuc => _make_stub("cmd_jmuc"),
    309129        {
    310130            summary     => "Jabber MUC related commands.",
     
    332152    );
    333153    BarnOwl::new_command(
    334         jroster => \&cmd_jroster,
     154        jroster => _make_stub("cmd_jroster"),
    335155        {
    336156            summary     => "Jabber roster related commands.",
     
    366186}
    367187
    368 sub cmd_login {
    369     my $cmd = shift;
    370     my $jidStr = shift;
    371     my $jid = new Net::Jabber::JID;
    372     $jid->SetJID($jidStr);
    373     my $password = '';
    374     $password = shift if @_;
    375 
    376     my $uid           = $jid->GetUserID();
    377     my $componentname = $jid->GetServer();
    378     my $resource      = $jid->GetResource();
    379 
    380     if ($resource eq '') {
    381         my $cjidStr = $conn->baseJIDExists($jidStr);
    382         if ($cjidStr) {
    383             die("Already logged in as $cjidStr.\n");
    384         }
    385     }
    386 
    387     $resource ||= 'barnowl';
    388     $jid->SetResource($resource);
    389     $jidStr = $jid->GetJID('full');
    390 
    391     if ( !$uid || !$componentname ) {
    392         die("usage: $cmd JID\n");
    393     }
    394 
    395     if ( $conn->jidActive($jidStr) ) {
    396         die("Already logged in as $jidStr.\n");
    397     } elsif ($conn->jidExists($jidStr)) {
    398         return $conn->tryReconnect($jidStr, 1);
    399     }
    400 
    401     my ( $server, $port ) = getServerFromJID($jid);
    402 
    403     $vars{jlogin_jid} = $jidStr;
    404     $vars{jlogin_connhash} = {
    405         hostname      => $server,
    406         tls           => 1,
    407         port          => $port,
    408         componentname => $componentname
    409     };
    410     $vars{jlogin_authhash} =
    411       { username => $uid,
    412         resource => $resource,
    413     };
    414 
    415     return do_login($password);
     188sub onGetQuickstart {
     189    return <<'EOF'
     190@b(Jabber:)
     191Type ':jabberlogin @b(username@mit.edu)' to log in to Jabber. The command
     192':jroster sub @b(somebody@gmail.com)' will request that they let you message
     193them. Once you get a message saying you are subscribed, you can message
     194them by typing ':jwrite @b(somebody@gmail.com)' or just 'j @b(somebody)'.
     195EOF
    416196}
    417197
    418 sub do_login {
    419     $vars{jlogin_password} = shift;
    420     $vars{jlogin_authhash}->{password} = sub { return $vars{jlogin_password} || '' };
    421     my $jidStr = $vars{jlogin_jid};
    422     if ( !$jidStr && $vars{jlogin_havepass}) {
    423         BarnOwl::error("Got password but have no JID!");
    424     }
    425     else
    426     {
    427         my $client = $conn->addConnection($jidStr);
    428 
    429         #XXX Todo: Add more callbacks.
    430         # * MUC presence handlers
    431         # We use the anonymous subrefs in order to have the correct behavior
    432         # when we reload
    433         $client->SetMessageCallBacks(
    434             chat      => sub { BarnOwl::Module::Jabber::process_incoming_chat_message(@_) },
    435             error     => sub { BarnOwl::Module::Jabber::process_incoming_error_message(@_) },
    436             groupchat => sub { BarnOwl::Module::Jabber::process_incoming_groupchat_message(@_) },
    437             headline  => sub { BarnOwl::Module::Jabber::process_incoming_headline_message(@_) },
    438             normal    => sub { BarnOwl::Module::Jabber::process_incoming_normal_message(@_) }
    439         );
    440         $client->SetPresenceCallBacks(
    441             available    => sub { BarnOwl::Module::Jabber::process_presence_available(@_) },
    442             unavailable  => sub { BarnOwl::Module::Jabber::process_presence_available(@_) },
    443             subscribe    => sub { BarnOwl::Module::Jabber::process_presence_subscribe(@_) },
    444             subscribed   => sub { BarnOwl::Module::Jabber::process_presence_subscribed(@_) },
    445             unsubscribe  => sub { BarnOwl::Module::Jabber::process_presence_unsubscribe(@_) },
    446             unsubscribed => sub { BarnOwl::Module::Jabber::process_presence_unsubscribed(@_) },
    447             error        => sub { BarnOwl::Module::Jabber::process_presence_error(@_) });
    448 
    449         my $status = $client->Connect( %{ $vars{jlogin_connhash} } );
    450         if ( !$status ) {
    451             $conn->removeConnection($jidStr);
    452             BarnOwl::error("We failed to connect.");
    453         } else {
    454             my @result = $client->AuthSend( %{ $vars{jlogin_authhash} } );
    455 
    456             if ( !@result || $result[0] ne 'ok' ) {
    457                 if ( !$vars{jlogin_havepass} && ( !@result || $result[0] eq '401' || $result[0] eq 'error') ) {
    458                     $vars{jlogin_havepass} = 1;
    459                     $conn->removeConnection($jidStr);
    460                     BarnOwl::start_password("Password for $jidStr: ", \&do_login );
    461                     return "";
    462                 }
    463                 $conn->removeConnection($jidStr);
    464                 BarnOwl::error( "Error in connect: " . join( " ", @result ) );
    465             } else {
    466                 $conn->setAuth(
    467                     $jidStr,
    468                     {   %{ $vars{jlogin_authhash} },
    469                         password => $vars{jlogin_password}
    470                     }
    471                 );
    472                 $client->onConnect($conn, $jidStr);
    473             }
    474         }
    475     }
    476     delete $vars{jlogin_jid};
    477     $vars{jlogin_password} =~ tr/\0-\377/x/ if $vars{jlogin_password};
    478     delete $vars{jlogin_password};
    479     delete $vars{jlogin_havepass};
    480     delete $vars{jlogin_connhash};
    481     delete $vars{jlogin_authhash};
    482 
    483     return "";
    484 }
    485 
    486 sub do_logout {
    487     my $jid = shift;
    488     my $disconnected = $conn->removeConnection($jid);
    489     queue_admin_msg("Jabber disconnected ($jid).") if $disconnected;
    490 }
    491 
    492 sub cmd_logout {
    493     return "You are not logged into Jabber." unless ($conn->connected() > 0);
    494     # Logged into multiple accounts
    495     if ( $conn->connected() > 1 ) {
    496         # Logged into multiple accounts, no accout specified.
    497         if ( !$_[1] ) {
    498             my $errStr =
    499               "You are logged into multiple accounts. Please specify an account to log out of.\n";
    500             foreach my $jid ( $conn->getJIDs() ) {
    501                 $errStr .= "\t$jid\n";
    502             }
    503             queue_admin_msg($errStr);
    504         }
    505         # Logged into multiple accounts, account specified.
    506         else {
    507             if ( $_[1] eq '-A' )    #All accounts.
    508             {
    509                 foreach my $jid ( $conn->getJIDs() ) {
    510                     do_logout($jid);
    511                 }
    512             }
    513             else                    #One account.
    514             {
    515                 my $jid = resolveConnectedJID( $_[1] );
    516                 do_logout($jid) if ( $jid ne '' );
    517             }
    518         }
    519     }
    520     else                            # Only one account logged in.
    521     {
    522         do_logout( ( $conn->getJIDs() )[0] );
    523     }
    524     return "";
    525 }
    526 
    527 sub cmd_jlist {
    528     if ( !( scalar $conn->getJIDs() ) ) {
    529         die("You are not logged in to Jabber.\n");
    530     }
    531     BarnOwl::popless_ztext( onGetBuddyList() );
    532 }
    533 
    534 sub cmd_jwrite {
    535     if ( !$conn->connected() ) {
    536         die("You are not logged in to Jabber.\n");
    537     }
    538 
    539     my $jwrite_to      = "";
    540     my $jwrite_from    = "";
    541     my $jwrite_sid     = "";
    542     my $jwrite_thread  = "";
    543     my $jwrite_subject = "";
    544     my $jwrite_body;
    545     my ($to, $from);
    546     my $jwrite_type    = "chat";
    547 
    548     my @args = @_;
    549     shift;
    550     local @ARGV = @_;
    551     my $gc;
    552     GetOptions(
    553         'thread=s'  => \$jwrite_thread,
    554         'subject=s' => \$jwrite_subject,
    555         'account=s' => \$from,
    556         'id=s'      => \$jwrite_sid,
    557         'message=s' => \$jwrite_body,
    558     ) or die("Usage: jwrite <jid> [-t <thread>] [-s <subject>] [-a <account>]\n");
    559     $jwrite_type = 'groupchat' if $gc;
    560 
    561     if ( scalar @ARGV != 1 ) {
    562         die("Usage: jwrite <jid> [-t <thread>] [-s <subject>] [-a <account>]\n");
    563     }
    564     else {
    565       $to = shift @ARGV;
    566     }
    567 
    568     my @candidates = guess_jwrite($from, $to);
    569 
    570     unless(scalar @candidates) {
    571         die("Unable to resolve JID $to\n");
    572     }
    573 
    574     @candidates = grep {defined $_->[0]} @candidates;
    575 
    576     unless(scalar @candidates) {
    577         if(!$from) {
    578             die("You must specify an account with -a\n");
    579         } else {
    580             die("Unable to resolve account $from\n");
    581         }
    582     }
    583 
    584 
    585     ($jwrite_from, $jwrite_to, $jwrite_type) = @{$candidates[0]};
    586 
    587     $vars{jwrite} = {
    588         to      => $jwrite_to,
    589         from    => $jwrite_from,
    590         sid     => $jwrite_sid,
    591         subject => $jwrite_subject,
    592         thread  => $jwrite_thread,
    593         type    => $jwrite_type
    594     };
    595 
    596     if (defined($jwrite_body)) {
    597         process_owl_jwrite($jwrite_body);
    598         return;
    599     }
    600 
    601     if(scalar @candidates > 1) {
    602         BarnOwl::message(
    603             "Warning: Guessing account and/or destination JID"
    604            );
    605     } else  {
    606         BarnOwl::message(
    607             "Type your message below.  End with a dot on a line by itself.  ^C will quit."
    608            );
    609     }
    610 
    611     my @cmd = ('jwrite', $jwrite_to, '-a', $jwrite_from);
    612     push @cmd, '-t', $jwrite_thread if $jwrite_thread;
    613     push @cmd, '-s', $jwrite_subject if $jwrite_subject;
    614 
    615     BarnOwl::start_edit_win(BarnOwl::quote(@cmd), \&process_owl_jwrite);
    616 }
    617 
    618 sub cmd_jmuc {
    619     die "You are not logged in to Jabber" unless $conn->connected();
    620     my $ocmd = shift;
    621     my $cmd  = shift;
    622     if ( !$cmd ) {
    623 
    624         #XXX TODO: Write general usage for jmuc command.
    625         return;
    626     }
    627 
    628     my %jmuc_commands = (
    629         join      => \&jmuc_join,
    630         part      => \&jmuc_part,
    631         invite    => \&jmuc_invite,
    632         configure => \&jmuc_configure,
    633         presence  => \&jmuc_presence
    634     );
    635     my $func = $jmuc_commands{$cmd};
    636     if ( !$func ) {
    637         die("jmuc: Unknown command: $cmd\n");
    638     }
    639 
    640     {
    641         local @ARGV = @_;
    642         my $jid;
    643         my $muc;
    644         my $m = BarnOwl::getcurmsg();
    645         if ( $m && $m->is_jabber && $m->{jtype} eq 'groupchat' ) {
    646             $muc = $m->{room};
    647             $jid = $m->{to};
    648         }
    649 
    650         my $getopt = Getopt::Long::Parser->new;
    651         $getopt->configure('pass_through', 'no_getopt_compat');
    652         $getopt->getoptions( 'account=s' => \$jid );
    653         $jid ||= defaultJID();
    654         if ($jid) {
    655             $jid = resolveConnectedJID($jid);
    656             return unless $jid;
    657         }
    658         else {
    659             die("You must specify an account with -a <jid>\n");
    660         }
    661         return $func->( $jid, $muc, @ARGV );
    662     }
    663 }
    664 
    665 sub jmuc_join {
    666     my ( $jid, $muc, @args ) = @_;
    667     local @ARGV = @args;
    668     my $password;
    669     GetOptions( 'password=s' => \$password );
    670 
    671     $muc = shift @ARGV
    672       or die("Usage: jmuc join <muc> [-p <password>] [-a <account>]\n");
    673 
    674     die("Error: Must specify a fully-qualified MUC name (e.g. barnowl\@conference.mit.edu)\n")
    675         unless $muc =~ /@/;
    676     $muc = Net::Jabber::JID->new($muc);
    677     $jid = Net::Jabber::JID->new($jid);
    678     $muc->SetResource($jid->GetJID('full')) unless length $muc->GetResource();
    679 
    680     $conn->getConnectionFromJID($jid)->MUCJoin(JID      => $muc,
    681                                                Password => $password,
    682                                                History  => {
    683                                                    MaxChars => 0
    684                                                   });
    685     $completion_jids{$muc->GetJID('base')} = 1;
    686     return;
    687 }
    688 
    689 sub jmuc_part {
    690     my ( $jid, $muc, @args ) = @_;
    691 
    692     $muc = shift @args if scalar @args;
    693     die("Usage: jmuc part [<muc>] [-a <account>]\n") unless $muc;
    694 
    695     if($conn->getConnectionFromJID($jid)->MUCLeave(JID => $muc)) {
    696         queue_admin_msg("$jid has left $muc.");
    697     } else {
    698         die("Error: Not joined to $muc\n");
    699     }
    700 }
    701 
    702 sub jmuc_invite {
    703     my ( $jid, $muc, @args ) = @_;
    704 
    705     my $invite_jid = shift @args;
    706     $muc = shift @args if scalar @args;
    707 
    708     die("Usage: jmuc invite <jid> [<muc>] [-a <account>]\n")
    709       unless $muc && $invite_jid;
    710 
    711     my $message = Net::Jabber::Message->new();
    712     $message->SetTo($muc);
    713     my $x = $message->NewChild('http://jabber.org/protocol/muc#user');
    714     $x->AddInvite();
    715     $x->GetInvite()->SetTo($invite_jid);
    716     $conn->getConnectionFromJID($jid)->Send($message);
    717     queue_admin_msg("$jid has invited $invite_jid to $muc.");
    718 }
    719 
    720 sub jmuc_configure {
    721     my ( $jid, $muc, @args ) = @_;
    722     $muc = shift @args if scalar @args;
    723     die("Usage: jmuc configure [<muc>]\n") unless $muc;
    724     my $iq = Net::Jabber::IQ->new();
    725     $iq->SetTo($muc);
    726     $iq->SetType('set');
    727     my $query = $iq->NewQuery("http://jabber.org/protocol/muc#owner");
    728     my $x     = $query->NewChild("jabber:x:data");
    729     $x->SetType('submit');
    730 
    731     $conn->getConnectionFromJID($jid)->Send($iq);
    732     queue_admin_msg("Accepted default instant configuration for $muc");
    733 }
    734 
    735 sub jmuc_presence_single {
    736     my $m = shift;
    737     my @jids = $m->Presence();
    738 
    739     my $presence = "JIDs present in " . $m->BaseJID;
    740     $completion_jids{$m->BaseJID} = 1;
    741     if($m->Anonymous) {
    742         $presence .= " [anonymous MUC]";
    743     }
    744     $presence .= "\n\t";
    745     $presence .= join("\n\t", map {pp_jid($m, $_);} @jids) . "\n";
    746     return $presence;
    747 }
    748 
    749 sub pp_jid {
    750     my ($m, $jid) = @_;
    751     my $nick = $jid->GetResource;
    752     my $full = $m->GetFullJID($jid);
    753     if($full && $full ne $nick) {
    754         return "$nick ($full)";
    755     } else {
    756         return "$nick";
    757     }
    758 }
    759 
    760 sub jmuc_presence {
    761     my ( $jid, $muc, @args ) = @_;
    762 
    763     $muc = shift @args if scalar @args;
    764     die("Usage: jmuc presence [<muc>]\n") unless $muc;
    765 
    766     if ($muc eq '-a') {
    767         my $str = "";
    768         foreach my $jid ($conn->getJIDs()) {
    769             $str .= BarnOwl::Style::boldify("Conferences for $jid:\n");
    770             my $connection = $conn->getConnectionFromJID($jid);
    771             foreach my $muc ($connection->MUCs) {
    772                 $str .= jmuc_presence_single($muc)."\n";
    773             }
    774         }
    775         BarnOwl::popless_ztext($str);
    776     }
    777     else {
    778         my $m = $conn->getConnectionFromJID($jid)->FindMUC(jid => $muc);
    779         die("No such muc: $muc\n") unless $m;
    780         BarnOwl::popless_ztext(jmuc_presence_single($m));
    781     }
    782 }
    783 
    784 
    785 #XXX TODO: Consider merging this with jmuc and selecting off the first two args.
    786 sub cmd_jroster {
    787     die "You are not logged in to Jabber" unless $conn->connected();
    788     my $ocmd = shift;
    789     my $cmd  = shift;
    790     if ( !$cmd ) {
    791 
    792         #XXX TODO: Write general usage for jroster command.
    793         return;
    794     }
    795 
    796     my %jroster_commands = (
    797         sub      => \&jroster_sub,
    798         unsub    => \&jroster_unsub,
    799         add      => \&jroster_add,
    800         remove   => \&jroster_remove,
    801         auth     => \&jroster_auth,
    802         deauth   => \&jroster_deauth
    803     );
    804     my $func = $jroster_commands{$cmd};
    805     if ( !$func ) {
    806         die("jroster: Unknown command: $cmd\n");
    807     }
    808 
    809     {
    810         local @ARGV = @_;
    811         my $jid;
    812         my $name;
    813         my @groups;
    814         my $purgeGroups;
    815         my $getopt = Getopt::Long::Parser->new;
    816         $getopt->configure('pass_through', 'no_getopt_compat');
    817         $getopt->getoptions(
    818             'account=s' => \$jid,
    819             'group=s' => \@groups,
    820             'purgegroups' => \$purgeGroups,
    821             'name=s' => \$name
    822         );
    823         $jid ||= defaultJID();
    824         if ($jid) {
    825             $jid = resolveConnectedJID($jid);
    826             return unless $jid;
    827         }
    828         else {
    829             die("You must specify an account with -a <jid>\n");
    830         }
    831         return $func->( $jid, $name, \@groups, $purgeGroups,  @ARGV );
    832     }
    833 }
    834 
    835 sub cmd_jaway {
    836     my $cmd = shift;
    837     local @ARGV = @_;
    838     my $getopt = Getopt::Long::Parser->new;
    839     my ($jid, $show);
    840     my $p = new Net::Jabber::Presence;
    841 
    842     $getopt->configure('pass_through', 'no_getopt_compat');
    843     $getopt->getoptions(
    844         'account=s' => \$jid,
    845         'show=s'    => \$show
    846     );
    847     $jid ||= defaultJID();
    848     if ($jid) {
    849         $jid = resolveConnectedJID($jid);
    850         return unless $jid;
    851     }
    852     else {
    853         die("You must specify an account with -a <jid>\n");
    854     }
    855 
    856     $p->SetShow($show eq "online" ? "" : $show) if $show;
    857     $p->SetStatus(join(' ', @ARGV)) if @ARGV;
    858     $conn->getConnectionFromJID($jid)->Send($p);
    859 }
    860 
    861 
    862 sub jroster_sub {
    863     my $jid = shift;
    864     my $name = shift;
    865     my @groups = @{ shift() };
    866     my $purgeGroups = shift;
    867     my $baseJID = baseJID($jid);
    868 
    869     my $roster = $conn->getRosterFromJID($jid);
    870 
    871     # Adding lots of users with the same name is a bad idea.
    872     $name = "" unless (1 == scalar(@ARGV));
    873 
    874     my $p = new Net::Jabber::Presence;
    875     $p->SetType('subscribe');
    876 
    877     foreach my $to (@ARGV) {
    878         jroster_add($jid, $name, \@groups, $purgeGroups, ($to)) unless ($roster->exists($to));
    879 
    880         $p->SetTo($to);
    881         $conn->getConnectionFromJID($jid)->Send($p);
    882         queue_admin_msg("You ($baseJID) have requested a subscription to ($to)'s presence.");
    883     }
    884 }
    885 
    886 sub jroster_unsub {
    887     my $jid = shift;
    888     my $name = shift;
    889     my @groups = @{ shift() };
    890     my $purgeGroups = shift;
    891     my $baseJID = baseJID($jid);
    892 
    893     my $p = new Net::Jabber::Presence;
    894     $p->SetType('unsubscribe');
    895     foreach my $to (@ARGV) {
    896         $p->SetTo($to);
    897         $conn->getConnectionFromJID($jid)->Send($p);
    898         queue_admin_msg("You ($baseJID) have unsubscribed from ($to)'s presence.");
    899     }
    900 }
    901 
    902 sub jroster_add {
    903     my $jid = shift;
    904     my $name = shift;
    905     my @groups = @{ shift() };
    906     my $purgeGroups = shift;
    907     my $baseJID = baseJID($jid);
    908 
    909     my $roster = $conn->getRosterFromJID($jid);
    910 
    911     # Adding lots of users with the same name is a bad idea.
    912     $name = "" unless (1 == scalar(@ARGV));
    913 
    914     $completion_jids{$baseJID} = 1;
    915     $completion_jids{$name} = 1 if $name;
    916 
    917     foreach my $to (@ARGV) {
    918         my %jq  = $roster->query($to);
    919         my $iq = new Net::Jabber::IQ;
    920         $iq->SetType('set');
    921         my $item = new XML::Stream::Node('item');
    922         $iq->NewChild('jabber:iq:roster')->AddChild($item);
    923 
    924         my %allGroups = ();
    925 
    926         foreach my $g (@groups) {
    927             $allGroups{$g} = $g;
    928         }
    929 
    930         unless ($purgeGroups) {
    931             foreach my $g (@{$jq{groups}}) {
    932                 $allGroups{$g} = $g;
    933             }
    934         }
    935 
    936         foreach my $g (keys %allGroups) {
    937             $item->add_child('group')->add_cdata($g);
    938         }
    939 
    940         $item->put_attrib(jid => $to);
    941         $item->put_attrib(name => $name) if $name;
    942         $conn->getConnectionFromJID($jid)->Send($iq);
    943         my $msg = "$baseJID: "
    944           . ($name ? "$name ($to)" : "($to)")
    945           . " is on your roster in the following groups: { "
    946           . join(" , ", keys %allGroups)
    947           . " }";
    948         queue_admin_msg($msg);
    949     }
    950 }
    951 
    952 sub jroster_remove {
    953     my $jid = shift;
    954     my $name = shift;
    955     my @groups = @{ shift() };
    956     my $purgeGroups = shift;
    957     my $baseJID = baseJID($jid);
    958 
    959     my $iq = new Net::Jabber::IQ;
    960     $iq->SetType('set');
    961     my $item = new XML::Stream::Node('item');
    962     $iq->NewChild('jabber:iq:roster')->AddChild($item);
    963     $item->put_attrib(subscription=> 'remove');
    964     foreach my $to (@ARGV) {
    965         $item->put_attrib(jid => $to);
    966         $conn->getConnectionFromJID($jid)->Send($iq);
    967         queue_admin_msg("You ($baseJID) have removed ($to) from your roster.");
    968     }
    969 }
    970 
    971 sub jroster_auth {
    972     my $jid = shift;
    973     my $name = shift;
    974     my @groups = @{ shift() };
    975     my $purgeGroups = shift;
    976     my $baseJID = baseJID($jid);
    977 
    978     my $p = new Net::Jabber::Presence;
    979     $p->SetType('subscribed');
    980     foreach my $to (@ARGV) {
    981         $p->SetTo($to);
    982         $conn->getConnectionFromJID($jid)->Send($p);
    983         queue_admin_msg("($to) has been subscribed to your ($baseJID) presence.");
    984     }
    985 }
    986 
    987 sub jroster_deauth {
    988     my $jid = shift;
    989     my $name = shift;
    990     my @groups = @{ shift() };
    991     my $purgeGroups = shift;
    992     my $baseJID = baseJID($jid);
    993 
    994     my $p = new Net::Jabber::Presence;
    995     $p->SetType('unsubscribed');
    996     foreach my $to (@ARGV) {
    997         $p->SetTo($to);
    998         $conn->getConnectionFromJID($jid)->Send($p);
    999         queue_admin_msg("($to) has been unsubscribed from your ($baseJID) presence.");
    1000     }
    1001 }
    1002 
    1003 ################################################################################
    1004 ### Owl Callbacks
    1005 sub process_owl_jwrite {
    1006     my $body = shift;
    1007 
    1008     my $j = new Net::Jabber::Message;
    1009     $body =~ s/\n\z//;
    1010     $j->SetMessage(
    1011         to   => $vars{jwrite}{to},
    1012         from => $vars{jwrite}{from},
    1013         type => $vars{jwrite}{type},
    1014         body => $body
    1015     );
    1016 
    1017     $j->SetThread( $vars{jwrite}{thread} )   if ( $vars{jwrite}{thread} );
    1018     $j->SetSubject( $vars{jwrite}{subject} ) if ( $vars{jwrite}{subject} );
    1019 
    1020     my $m = j2o( $j, { direction => 'out' } );
    1021     if ( $vars{jwrite}{type} ne 'groupchat') {
    1022         BarnOwl::queue_message($m);
    1023     }
    1024 
    1025     $j->RemoveFrom(); # Kludge to get around gtalk's random bits after the resource.
    1026     if ($vars{jwrite}{sid} && $conn->sidExists( $vars{jwrite}{sid} )) {
    1027         $conn->getConnectionFromSid($vars{jwrite}{sid})->Send($j);
    1028     }
    1029     else {
    1030         $conn->getConnectionFromJID($vars{jwrite}{from})->Send($j);
    1031     }
    1032 
    1033     delete $vars{jwrite};
    1034     BarnOwl::message("");   # Kludge to make the ``type your message...'' message go away
    1035 }
    1036 
    1037 ### XMPP Callbacks
    1038 
    1039 sub process_incoming_chat_message {
    1040     my ( $sid, $j ) = @_;
    1041     if ($j->DefinedBody() || BarnOwl::getvar('jabber:spew') eq 'on') {
    1042         BarnOwl::queue_message( j2o( $j, { direction => 'in',
    1043                                            sid => $sid } ) );
    1044     }
    1045 }
    1046 
    1047 sub process_incoming_error_message {
    1048     my ( $sid, $j ) = @_;
    1049     my %jhash = j2hash( $j, { direction => 'in',
    1050                               sid => $sid } );
    1051     $jhash{type} = 'admin';
    1052    
    1053     BarnOwl::queue_message( BarnOwl::Message->new(%jhash) );
    1054 }
    1055 
    1056 sub process_incoming_groupchat_message {
    1057     my ( $sid, $j ) = @_;
    1058 
    1059     # HACK IN PROGRESS (ignoring delayed messages)
    1060     return if ( $j->DefinedX('jabber:x:delay') && $j->GetX('jabber:x:delay') );
    1061     BarnOwl::queue_message( j2o( $j, { direction => 'in',
    1062                                    sid => $sid } ) );
    1063 }
    1064 
    1065 sub process_incoming_headline_message {
    1066     my ( $sid, $j ) = @_;
    1067     BarnOwl::queue_message( j2o( $j, { direction => 'in',
    1068                                    sid => $sid } ) );
    1069 }
    1070 
    1071 sub process_incoming_normal_message {
    1072     my ( $sid, $j ) = @_;
    1073     my %jhash = j2hash( $j, { direction => 'in',
    1074                               sid => $sid } );
    1075 
    1076     # XXX TODO: handle things such as MUC invites here.
    1077 
    1078     #    if ($j->HasX('http://jabber.org/protocol/muc#user'))
    1079     #    {
    1080     #   my $x = $j->GetX('http://jabber.org/protocol/muc#user');
    1081     #   if ($x->HasChild('invite'))
    1082     #   {
    1083     #       $props
    1084     #   }
    1085     #    }
    1086     #
    1087     if ($j->DefinedBody() || BarnOwl::getvar('jabber:spew') eq 'on') {
    1088         BarnOwl::queue_message( BarnOwl::Message->new(%jhash) );
    1089     }
    1090 }
    1091 
    1092 sub process_muc_presence {
    1093     my ( $sid, $p ) = @_;
    1094     return unless ( $p->HasX('http://jabber.org/protocol/muc#user') );
    1095 }
    1096 
    1097 
    1098 sub process_presence_available {
    1099     my ( $sid, $p ) = @_;
    1100     my $from = $p->GetFrom('jid')->GetJID('base');
    1101     $completion_jids{$from} = 1;
    1102     return unless (BarnOwl::getvar('jabber:show_logins') eq 'on');
    1103     my $to = $p->GetTo();
    1104     my $type = $p->GetType();
    1105     my %props = (
    1106         to => $to,
    1107         from => $p->GetFrom(),
    1108         recipient => $to,
    1109         sender => $from,
    1110         type => 'jabber',
    1111         jtype => $p->GetType(),
    1112         status => $p->GetStatus(),
    1113         show => $p->GetShow(),
    1114         xml => $p->GetXML(),
    1115         direction => 'in');
    1116 
    1117     if ($type eq '' || $type eq 'available') {
    1118         $props{body} = "$from is now online. ";
    1119         $props{loginout} = 'login';
    1120     }
    1121     else {
    1122         $props{body} = "$from is now offline. ";
    1123         $props{loginout} = 'logout';
    1124     }
    1125     BarnOwl::queue_message(BarnOwl::Message->new(%props));
    1126 }
    1127 
    1128 sub process_presence_subscribe {
    1129     my ( $sid, $p ) = @_;
    1130     my $from = $p->GetFrom();
    1131     my $to = $p->GetTo();
    1132     my %props = (
    1133         to => $to,
    1134         from => $from,
    1135         xml => $p->GetXML(),
    1136         type => 'admin',
    1137         adminheader => 'Jabber presence: subscribe',
    1138         direction => 'in');
    1139 
    1140     $props{body} = "Allow user ($from) to subscribe to your ($to) presence?\n" .
    1141                    "(Answer with the `yes' or `no' commands)";
    1142     $props{yescommand} = BarnOwl::quote('jroster', 'auth', $from, '-a', $to);
    1143     $props{nocommand} = BarnOwl::quote('jroster', 'deauth', $from, '-a', $to);
    1144     $props{question} = "true";
    1145     BarnOwl::queue_message(BarnOwl::Message->new(%props));
    1146 }
    1147 
    1148 sub process_presence_unsubscribe {
    1149     my ( $sid, $p ) = @_;
    1150     my $from = $p->GetFrom();
    1151     my $to = $p->GetTo();
    1152     my %props = (
    1153         to => $to,
    1154         from => $from,
    1155         xml => $p->GetXML(),
    1156         type => 'admin',
    1157         adminheader => 'Jabber presence: unsubscribe',
    1158         direction => 'in');
    1159 
    1160     $props{body} = "The user ($from) has been unsubscribed from your ($to) presence.\n";
    1161     BarnOwl::queue_message(BarnOwl::Message->new(%props));
    1162 
    1163     # Find a connection to reply with.
    1164     foreach my $jid ($conn->getJIDs()) {
    1165         my $cJID = new Net::Jabber::JID;
    1166         $cJID->SetJID($jid);
    1167         if ($to eq $cJID->GetJID('base') ||
    1168             $to eq $cJID->GetJID('full')) {
    1169             my $reply = $p->Reply(type=>"unsubscribed");
    1170             $conn->getConnectionFromJID($jid)->Send($reply);
    1171             return;
    1172         }
    1173     }
    1174 }
    1175 
    1176 sub process_presence_subscribed {
    1177     my ( $sid, $p ) = @_;
    1178     queue_admin_msg("ignoring:".$p->GetXML()) if BarnOwl::getvar('jabber:spew') eq 'on';
    1179     # RFC 3921 says we should respond to this with a "subscribe"
    1180     # but this causes a flood of sub/sub'd presence packets with
    1181     # some servers, so we won't. We may want to detect this condition
    1182     # later, and have per-server settings.
    1183     return;
    1184 }
    1185 
    1186 sub process_presence_unsubscribed {
    1187     my ( $sid, $p ) = @_;
    1188     queue_admin_msg("ignoring:".$p->GetXML()) if BarnOwl::getvar('jabber:spew') eq 'on';
    1189     # RFC 3921 says we should respond to this with a "subscribe"
    1190     # but this causes a flood of unsub/unsub'd presence packets with
    1191     # some servers, so we won't. We may want to detect this condition
    1192     # later, and have per-server settings.
    1193     return;
    1194 }
    1195 
    1196 sub process_presence_error {
    1197     my ( $sid, $p ) = @_;
    1198     my $code = $p->GetErrorCode();
    1199     my $error = $p->GetError();
    1200     BarnOwl::error("Jabber: $code $error");
    1201 }
    1202 
    1203 
    1204 ### Helper functions
    1205 
    1206 sub j2hash {
    1207     my $j   = shift;
    1208     my %props = (type => 'jabber',
    1209                  dir  => 'none',
    1210                  %{$_[0]});
    1211 
    1212     my $dir = $props{direction};
    1213 
    1214     my $jtype = $props{jtype} = $j->GetType();
    1215     my $from = $j->GetFrom('jid');
    1216     my $to   = $j->GetTo('jid');
    1217 
    1218     $props{from} = $from->GetJID('full');
    1219     $props{to}   = $to->GetJID('full');
    1220 
    1221     $props{recipient}  = $to->GetJID('base');
    1222     $props{sender}     = $from->GetJID('base');
    1223     $props{subject}    = $j->GetSubject() if ( $j->DefinedSubject() );
    1224     $props{thread}     = $j->GetThread() if ( $j->DefinedThread() );
    1225     if ( $j->DefinedBody() ) {
    1226         $props{body}   = $j->GetBody();
    1227         $props{body}  =~ s/\xEF\xBB\xBF//g; # Strip stray Byte-Order-Marks.
    1228     }
    1229     $props{error}      = $j->GetError() if ( $j->DefinedError() );
    1230     $props{error_code} = $j->GetErrorCode() if ( $j->DefinedErrorCode() );
    1231     $props{xml}        = $j->GetXML();
    1232 
    1233     if ( $jtype eq 'groupchat' ) {
    1234         my $nick = $props{nick} = $from->GetResource();
    1235         my $room = $props{room} = $from->GetJID('base');
    1236         $completion_jids{$room} = 1;
    1237 
    1238         my $muc;
    1239         if ($dir eq 'in') {
    1240             my $connection = $conn->getConnectionFromSid($props{sid});
    1241             $muc = $connection->FindMUC(jid => $from);
    1242         } else {
    1243             my $connection = $conn->getConnectionFromJID($props{from});
    1244             $muc = $connection->FindMUC(jid => $to);
    1245         }
    1246         $props{from} = $muc->GetFullJID($from) || $props{from};
    1247         $props{sender} = $nick || $room;
    1248         $props{recipient} = $room;
    1249 
    1250         if ( $props{subject} && !$props{body} ) {
    1251             $props{body} =
    1252               '[' . $nick . " has set the topic to: " . $props{subject} . "]";
    1253         }
    1254     }
    1255     elsif ( $jtype eq 'headline' ) {
    1256         ;
    1257     }
    1258     elsif ( $jtype eq 'error' ) {
    1259         $props{body}     = "Error "
    1260           . $props{error_code}
    1261           . " sending to "
    1262           . $props{from} . "\n"
    1263           . $props{error};
    1264     }
    1265     else { # chat, or normal (default)
    1266         $props{private} = 1;
    1267 
    1268         my $connection;
    1269         if ($dir eq 'in') {
    1270             $connection = $conn->getConnectionFromSid($props{sid});
    1271         }
    1272         else {
    1273             $connection = $conn->getConnectionFromJID($props{from});
    1274         }
    1275 
    1276         # Check to see if we're doing personals with someone in a muc.
    1277         # If we are, show the full jid because the base jid is the room.
    1278         if ($connection) {
    1279             $props{sender} = $props{from}
    1280               if ($connection->FindMUC(jid => $from));
    1281             $props{recipient} = $props{to}
    1282               if ($connection->FindMUC(jid => $to));
    1283         }
    1284 
    1285         # Populate completion.
    1286         if ($dir eq 'in') {
    1287             $completion_jids{ $props{sender} }= 1;
    1288         }
    1289         else {
    1290             $completion_jids{ $props{recipient} } = 1;
    1291         }
    1292     }
    1293 
    1294     return %props;
    1295 }
    1296 
    1297 sub j2o {
    1298     return BarnOwl::Message->new( j2hash(@_) );
    1299 }
    1300 
    1301 sub queue_admin_msg {
    1302     my $err = shift;
    1303     BarnOwl::admin_message("Jabber", $err);
    1304 }
    1305 
    1306 sub getServerFromJID {
    1307     my $jid = shift;
    1308     my $res = new Net::DNS::Resolver;
    1309     my $packet =
    1310       $res->search( '_xmpp-client._tcp.' . $jid->GetServer(), 'srv' );
    1311 
    1312     if ($packet)    # Got srv record.
    1313     {
    1314         my @answer = $packet->answer;
    1315         return $answer[0]{target}, $answer[0]{port};
    1316     }
    1317 
    1318     return $jid->GetServer(), 5222;
    1319 }
    1320 
    1321 sub defaultJID {
    1322     return ( $conn->getJIDs() )[0] if ( $conn->connected() == 1 );
    1323     return;
    1324 }
    1325 
    1326 sub baseJID {
    1327     my $givenJIDStr = shift;
    1328     my $givenJID    = new Net::Jabber::JID;
    1329     $givenJID->SetJID($givenJIDStr);
    1330     return $givenJID->GetJID('base');
    1331 }
    1332 
    1333 sub resolveConnectedJID {
    1334     my $givenJIDStr = shift;
    1335     my $loose = shift || 0;
    1336     my $givenJID    = new Net::Jabber::JID;
    1337     $givenJID->SetJID($givenJIDStr);
    1338 
    1339     # Account fully specified.
    1340     if ( $givenJID->GetResource() ) {
    1341         # Specified account exists
    1342         return $givenJIDStr if ($conn->jidExists($givenJIDStr) );
    1343         return resolveConnectedJID($givenJID->GetJID('base')) if $loose;
    1344         die("Invalid account: $givenJIDStr\n");
    1345     }
    1346 
    1347     # Disambiguate.
    1348     else {
    1349         my $JIDMatchingJID = "";
    1350         my $strMatchingJID = "";
    1351         my $JIDMatches = "";
    1352         my $strMatches = "";
    1353         my $JIDAmbiguous = 0;
    1354         my $strAmbiguous = 0;
    1355 
    1356         foreach my $jid ( $conn->getJIDs() ) {
    1357             my $cJID = new Net::Jabber::JID;
    1358             $cJID->SetJID($jid);
    1359             if ( $givenJIDStr eq $cJID->GetJID('base') ) {
    1360                 $JIDAmbiguous = 1 if ( $JIDMatchingJID ne "" );
    1361                 $JIDMatchingJID = $jid;
    1362                 $JIDMatches .= "\t$jid\n";
    1363             }
    1364             if ( $cJID->GetJID('base') =~ /$givenJIDStr/ ) {
    1365                 $strAmbiguous = 1 if ( $strMatchingJID ne "" );
    1366                 $strMatchingJID = $jid;
    1367                 $strMatches .= "\t$jid\n";
    1368             }
    1369         }
    1370 
    1371         # Need further disambiguation.
    1372         if ($JIDAmbiguous) {
    1373             my $errStr =
    1374                 "Ambiguous account reference. Please specify a resource.\n";
    1375             die($errStr.$JIDMatches);
    1376         }
    1377 
    1378         # It's this one.
    1379         elsif ($JIDMatchingJID ne "") {
    1380             return $JIDMatchingJID;
    1381         }
    1382 
    1383         # Further resolution by substring.
    1384         elsif ($strAmbiguous) {
    1385             my $errStr =
    1386                 "Ambiguous account reference. Please be more specific.\n";
    1387             die($errStr.$strMatches);
    1388         }
    1389 
    1390         # It's this one, by substring.
    1391         elsif ($strMatchingJID ne "") {
    1392             return $strMatchingJID;
    1393         }
    1394 
    1395         # Not one of ours.
    1396         else {
    1397             die("Invalid account: $givenJIDStr\n");
    1398         }
    1399 
    1400     }
    1401     return "";
    1402 }
    1403 
    1404 sub resolveDestJID {
    1405     my ($to, $from) = @_;
    1406     my $jid = Net::Jabber::JID->new($to);
    1407 
    1408     my $roster = $conn->getRosterFromJID($from);
    1409     my @jids = $roster->jids('all');
    1410     for my $j (@jids) {
    1411         if(($roster->query($j, 'name') || $j->GetUserID()) eq $to) {
    1412             return $j->GetJID('full');
    1413         } elsif($j->GetJID('base') eq baseJID($to)) {
    1414             return $jid->GetJID('full');
    1415         }
    1416     }
    1417 
    1418     # If we found nothing being clever, check to see if our input was
    1419     # sane enough to look like a jid with a UserID.
    1420     return $jid->GetJID('full') if $jid->GetUserID();
    1421     return undef;
    1422 }
    1423 
    1424 sub resolveType {
    1425     my $to = shift;
    1426     my $from = shift;
    1427     return unless $from;
    1428     my @mucs = $conn->getConnectionFromJID($from)->MUCs;
    1429     if(grep {$_->BaseJID eq $to } @mucs) {
    1430         return 'groupchat';
    1431     } else {
    1432         return 'chat';
    1433     }
    1434 }
    1435 
    1436 sub guess_jwrite {
    1437     # Heuristically guess what jids a jwrite was meant to be going to/from
    1438     my ($from, $to) = (@_);
    1439     my ($from_jid, $to_jid);
    1440     my @matches;
    1441     if($from) {
    1442         $from_jid = resolveConnectedJID($from, 1);
    1443         die("Unable to resolve account $from\n") unless $from_jid;
    1444         $to_jid = resolveDestJID($to, $from_jid);
    1445         push @matches, [$from_jid, $to_jid] if $to_jid;
    1446     } else {
    1447         for my $f ($conn->getJIDs) {
    1448             $to_jid = resolveDestJID($to, $f);
    1449             if(defined($to_jid)) {
    1450                 push @matches, [$f, $to_jid];
    1451             }
    1452         }
    1453         if($to =~ /@/) {
    1454             push @matches, [$_, $to]
    1455                for ($conn->getJIDs);
    1456         }
    1457     }
    1458 
    1459     for my $m (@matches) {
    1460         my $type = resolveType($m->[1], $m->[0]);
    1461         push @$m, $type;
    1462     }
    1463 
    1464     return @matches;
    1465 }
    1466 
    1467 ################################################################################
    1468 ### Completion
    1469 
    1470 sub complete_user_or_muc { return keys %completion_jids; }
    1471 sub complete_account { return $conn->getJIDs(); }
    1472 
    1473 sub complete_jwrite {
    1474     my $ctx = shift;
    1475     return complete_flags($ctx,
    1476                           [qw(-t -i -s)],
    1477                           {
    1478                               "-a" => \&complete_account,
    1479                           },
    1480                           \&complete_user_or_muc
    1481         );
    1482 }
    1483 
    1484 sub complete_jabberlogout {
    1485     my $ctx = shift;
    1486     if($ctx->word == 1) {
    1487         return ("-A", complete_account() );
    1488     } else {
    1489         return ();
    1490     }
    1491 }
    1492 
    1493 BarnOwl::Completion::register_completer(jwrite => sub { BarnOwl::Module::Jabber::complete_jwrite(@_) });
    1494 BarnOwl::Completion::register_completer(jabberlogout => sub { BarnOwl::Module::Jabber::complete_jabberlogout(@_) });
    1495 
    14961981;
  • perl/modules/Jabber/lib/BarnOwl/Module/Jabber/Connection.pm

    rc6adf17 r3e34a69  
    146146    my $status = $self->Process(0);
    147147    if ( !defined($status) ) {
    148         $BarnOwl::Module::Jabber::conn->scheduleReconnect($jid);
     148        $BarnOwl::Module::Jabber::Impl::conn->scheduleReconnect($jid);
    149149    }
    150150}
     
    191191        my %jq  = $roster->query($buddy);
    192192        my $name = $jq{name} || $buddy->GetUserID();
    193         $BarnOwl::Module::Jabber::completion_jids{$name} = 1;
    194         $BarnOwl::Module::Jabber::completion_jids{$buddy->GetJID()} = 1;
    195     }
    196     $BarnOwl::Module::Jabber::vars{idletime} |= BarnOwl::getidletime();
    197     unless (exists $BarnOwl::Module::Jabber::vars{keepAliveTimer}) {
    198         $BarnOwl::Module::Jabber::vars{keepAliveTimer} =
     193        $BarnOwl::Module::Jabber::Impl::completion_jids{$name} = 1;
     194        $BarnOwl::Module::Jabber::Impl::completion_jids{$buddy->GetJID()} = 1;
     195    }
     196    $BarnOwl::Module::Jabber::Impl::vars{idletime} |= BarnOwl::getidletime();
     197    unless (exists $BarnOwl::Module::Jabber::Impl::vars{keepAliveTimer}) {
     198        $BarnOwl::Module::Jabber::Impl::vars{keepAliveTimer} =
    199199            BarnOwl::Timer->new({
    200200                'name' => "Jabber ($fullJid) keepAliveTimer",
    201201                'after' => 5,
    202202                'interval' => 5,
    203                 'cb' => sub { BarnOwl::Module::Jabber::do_keep_alive_and_auto_away(@_) }
     203                'cb' => sub { BarnOwl::Module::Jabber::Impl::do_keep_alive_and_auto_away(@_) }
    204204                                });
    205205    }
  • .gitignore

    rf93cc34 r1c22155  
    22*.o
    33*.par
    4 *~
    5 .#*
    6 .*.swp
    74.deps
     5/bin/
    86META.yml
     7MYMETA.yml
    98Makefile
    109Makefile.in
    1110Makefile.old
    1211TAGS
    13 \#*#
    1412aclocal.m4
    1513autom4te.cache
    16 barnowl.bin
    17 tester.bin
    18 zcrypt
     14barnowl
    1915blib
    2016config.cache
    2117config.h
    2218config.h.in
     19config.h.in~
    2320config.log
    2421config.status
     
    2623core
    2724depcomp
     25gmarshal_funcs.c
     26gmarshal_funcs.h
     27inc/
    2828install-sh
    2929jabber.log
     
    3232owl_prototypes.h.new
    3333perlglue.c
    34 perlwrap.c
    3534pm_to_blib
     35runtests.sh.log
     36runtests.sh.trs
    3637stamp-h1
     38test-driver
     39test-suite.log
     40tester
    3741varstubs.c
     42zcrypt
  • AUTHORS

    r1d2c4c3 r80c0fc7  
    33
    44The following people have provided patches or other contributions:
     5  Alex Vandiver
     6  Kevin Chen
     7  Arun Tharuvai
    58  Sam Hartman
    6   Alex Vandiver
    7   Geoffrey Thomas
    89  Derrick Brashear
    910  David Glasser
     11  Eric Price
    1012  Matthew Goldstein
    11   Arun Tharuvai
    12   Kevin Chen
    13   Eric Price
     13  Geoffrey Thomas
     14  Anders Kaseorg
     15  Greg Price
     16  Chris Lesniewski-Laas
     17  Alex Dehnert
     18  Edward Z. Yang
     19  Karl Ramm
     20  Evan Broder
     21  David Benjamin
     22  Cathy Zhang
     23  Joshua Oreman
     24  Leonid Grinberg
     25  Kevin Riggle
     26  Brian Sniffen
     27  William Throwe
     28  Jason Gross
     29  Adam Glasgall
     30  Tim Hill
     31  DD Liu
     32  Betsy Riley
     33  Robert Jacobs
    1434
    15 BarnOwl is based on code from Owl, which was originally primarly
     35BarnOwl is based on code from Owl, which was originally primarily
    1636written by James Kretchmar.  Erik Nygren also made substantial
    17 contributions and improvemnts to the program.
     37contributions and improvements to the program.
    1838
    19 The following people provided patches and other techincal support for
     39The following people provided patches and other technical support for
    2040Owl:
    2141
     
    3050  Mark Eichin
    3151
    32 Mark Eichin is also maintaining the debian package of Owl.
     52Mark Eichin is also maintaining the Debian package of Owl.
    3353
    3454The following people helped with beta testing the earliest versions of
  • COPYING

    rbbd0cf1 rccc182c  
    552552======================================================================
    553553
    554 Files under perl/modules/Facebook/lib/Facebook and
    555 perl/modules/Facebook/lib/Ouch.pm are copyright (c) 2010 Plain Black
    556 Corporation.
     554Files under perl/modules/Facebook/lib/Facebook are copyright (c) 2010 Plain
     555Black Corporation.
    557556
    558557This software is copyright (c) 2010 by Plain Black Corporation.
     
    934933
    935934The End
    936 
    937 ======================================================================
    938 
    939 The file perl/modules/Facebook/lib/AnyEvent/HTTP.pm is copyright (c)
    940 Marc Lehmann.
    941 
    942 This module is licensed under the same terms as perl itself.
    943 
    944 ======================================================================
    945 
    946 The file perl/modules/Facebook/lib/URI/Encode.pm is copyright (c)
    947 2010, Mithun Ayachit ``<mithun@cpan.org>''. All rights reserved.
    948 
    949 This module is free software; you can redistribute it and/or modify it
    950 under the same terms as Perl itself. See perlartistic.
  • ChangeLog

    r65ff3f4 r1b17f50  
     11.9
     2 * Add getnumlines() to perl interface -asedeno@mit.edu
     3 * Include names of invalid filters on filter errors -adehnert@mit.edu
     4 * Don't incorrectly mark decryption failures as decrypted -davidben@mit.edu
     5 * Hide the default cursor when possible -davidben@mit.edu
     6 * Complete viewperson and vp as viewuser and vu -davidben@mit.edu
     7 * Set z_charset = ZCHARSET_UTF_8 -andersk@mit.edu
     8 * Allow zsender spoofing on cross-realm classes -andersk@mit.edu
     9 * Append the realm to the zsender if missing -andersk@mit.edu
     10 * Redisplay on setting colorztext -jgross@mit.edu
     11 * Rename default config file to .owl/init.pl -kevinr@free-dissociation.com
     12 * Add completion for jabberlogout -adehnert@mit.edu
     13 * Switch to interactive context before sourcing the startup file -davidben@mit.edu
     14 * Add completion for reload-module -adehnert@mit.edu
     15 * editwin callback for canceling the editwin -jgross@mit.edu
     16 * Fix dirtying windows inside a redraw handler -davidben@mit.edu
     17 * Facebook module -ezyang@mit.edu
     18 * Complete unstartup command just like startup command -jgross@mit.edu
     19 * Fix the description of disable-ctrl-d -jgross@mit.edu
     20 * Use wbkgrndset instead of wbkgdset in _owl_fmtext_wcolor_set -davidben@mit.edu
     21 * Show the time zone in :info -jgross@mit.edu
     22 * Treat [!.?]" as end of sentence in edit:fill-paragraph -jgross@mit.edu
     23 * Correctly display multiline fields in :info -jgross@mit.edu
     24
     251.8.1
     26 * Only add outgoing messages for personal part of half-personal messages -andersk@mit.edu
     27 * Don’t write CC: line on zwrite -C '' -andersk@mit.edu
     28 * Don’t send public pings on zwrite '' or zwrite @REALM -andersk@mit.edu
     29 * Don’t treat zwrite '' as personal -andersk@mit.edu
     30 * Stop pretending to support zwrite * -andersk@mit.edu
     31 * Show foreign realms on non-personal zephyrs like Owl did -andersk@mit.edu
     32 * Fix memory leak in zcrypt -davidben@mit.edu
     33 * Don't attempt to switch filters in :view -d if invalid -davidben@mit.edu
     34 * Fixed typo in unbindkey usage error -rileyb@mit.edu
     35 * Fix bug generating filter text in 256-color mode -asedeno@mit.edu
     36 * Remove ^noc from reply-lockout -geofft@mit.edu
     37 * Avoid quadratic loops when receiving zephyrs -andersk@mit.edu
     38 * Fix hang on empty zcrypt messages -adehnert@MIT.EDU
     39
    1401.8
    241 * Compute the home directory in zcrypt consistently with BarnOwl -davidben@mit.edu
  • Makefile.am

    rc266281 ra223b6b  
    44GIT_FLAGS := $(if $(GIT_DESCRIPTION),-DGIT_VERSION=$(GIT_DESCRIPTION:barnowl-%=%))
    55
    6 bin_PROGRAMS = barnowl.bin
     6bin_PROGRAMS = bin/barnowl
    77if ENABLE_ZCRYPT
    88bin_PROGRAMS += zcrypt
     
    1111zcrypt_SOURCES = zcrypt.c filterproc.c
    1212
    13 check_PROGRAMS = tester.bin
     13check_PROGRAMS = bin/tester
     14dist_check_DATA = t
     15dist_check_SCRIPTS = runtests.sh
    1416
    15 barnowl_bin_SOURCES = $(BASE_SRCS) \
    16      owl.h owl_perl.h config.h \
    17      owl.c \
    18      $(GEN_C) $(GEN_H)
     17noinst_SCRIPTS = barnowl
     18check_SCRIPTS = tester
    1919
    20 man_MANS = doc/barnowl.1
    21 doc_DATA = doc/intro.txt doc/advanced.txt
     20barnowl tester: %: barnowl-wrapper.in bin/% Makefile
     21        sed \
     22            -e 's,[@]abs_srcdir[@],$(abs_srcdir),g' \
     23            -e 's,[@]abs_builddir[@],$(abs_builddir),g' \
     24            $< > $@
     25        chmod +x $@
    2226
    23 barnowl_bin_LDADD = compat/libcompat.a libfaim/libfaim.a
     27bin_barnowl_SOURCES = $(BASE_SRCS) \
     28     owl.h owl_perl.h \
     29     owl.c
     30nodist_bin_barnowl_SOURCES = $(GEN_C) $(GEN_H)
    2431
    25 tester_bin_SOURCES = $(BASE_SRCS) \
    26      owl.h owl_perl.h config.h \
    27      $(GEN_C) $(GEN_H) \
     32dist_man_MANS = doc/barnowl.1
     33dist_doc_DATA = doc/intro.txt doc/advanced.txt
     34
     35bin_barnowl_LDADD = compat/libcompat.a libfaim/libfaim.a
     36
     37bin_tester_SOURCES = $(BASE_SRCS) \
     38     owl.h owl_perl.h \
    2839     tester.c
     40nodist_bin_tester_SOURCES = $(GEN_C) $(GEN_H)
    2941
    30 tester_bin_LDADD = compat/libcompat.a libfaim/libfaim.a
     42bin_tester_LDADD = compat/libcompat.a libfaim/libfaim.a
    3143
    3244TESTS=runtests.sh
    3345
    34 AM_CPPFLAGS = -I$(top_srcdir)/ \
     46AM_CPPFLAGS = \
    3547           -I$(top_srcdir)/libfaim/ \
    3648           -DDATADIR='"$(pkgdatadir)"' \
     
    3951
    4052CODELIST_SRCS=message.c mainwin.c popwin.c zephyr.c messagelist.c \
    41      commands.c global.c text.c fmtext.c editwin.c util.c logging.c \
     53     commands.c global.c text.c fmtext.c editwin.c \
     54     util.c logging.c \
    4255     perlconfig.c keys.c functions.c zwrite.c viewwin.c help.c filter.c \
    4356     regex.c history.c view.c dict.c variable.c filterelement.c pair.c \
     
    4558     aim.c buddy.c buddylist.c style.c errqueue.c \
    4659     zbuddylist.c popexec.c select.c wcwidth.c \
    47      mainpanel.c msgwin.c sepbar.c editcontext.c signal.c
     60     mainpanel.c msgwin.c sepbar.c editcontext.c signal.c closures.c
    4861
    49 NORMAL_SRCS = filterproc.c window.c windowcb.c
     62NORMAL_SRCS = filterproc.c filterproc.h window.c window.h windowcb.c
    5063
    5164BASE_SRCS = $(CODELIST_SRCS) $(NORMAL_SRCS)
    5265
    53 GEN_C = varstubs.c perlglue.c
    54 GEN_H = owl_prototypes.h
     66GEN_C = varstubs.c perlglue.c gmarshal_funcs.c
     67GEN_H = owl_prototypes.h owl_prototypes.h.new gmarshal_funcs.h
    5568
    5669BUILT_SOURCES = $(GEN_C) $(GEN_H)
     
    6578proto: owl_prototypes.h
    6679
    67 perlglue.c: perlglue.xs $(TYPEMAP)
    68         $(AM_V_GEN)perl $(XSUBPPDIR)/xsubpp $(XSUBPPFLAGS) -prototypes perlglue.xs > perlglue.c
     80perlglue.c: perlglue.xs typemap
     81        $(AM_V_GEN)perl $(XSUBPPDIR)/xsubpp $(XSUBPPFLAGS) -prototypes $< > $@
    6982
    7083varstubs.c: stubgen.pl variable.c
     
    7487        $(AM_V_GEN)perl $< $(sort $(filter-out $<,$+)) > $@
    7588
     89gmarshal_funcs.h: marshal_types
     90        glib-genmarshal --header $< > $@
     91gmarshal_funcs.c: marshal_types
     92        glib-genmarshal --body $< > $@
     93
    7694# For emacs flymake-mode
    7795check-syntax: proto
    7896        $(COMPILE) -Wall -Wextra -pedantic -fsyntax-only $(CHK_SOURCES)
    7997
    80 install-data-local:
    81         $(mkinstalldirs) ${DESTDIR}${pkgdatadir}/lib
    82         (cd perl/lib && tar -cf - . ) | (cd ${DESTDIR}${pkgdatadir}/lib && tar -xf - )
    83 
    84 do_transform = $(shell echo '$(1)' | sed '$(transform)')
    85 install-exec-hook:
    86         mv -f $(DESTDIR)$(bindir)/$(call do_transform,barnowl.bin) \
    87               $(DESTDIR)$(bindir)/$(call do_transform,barnowl)
     98CLEANFILES = $(BUILT_SOURCES) $(noinst_SCRIPTS) $(check_SCRIPTS)
     99EXTRA_DIST = \
     100    autogen.sh \
     101    barnowl-wrapper.in \
     102    codelist.pl \
     103    doc/code.txt \
     104    doc/owl-window.txt \
     105    doc/releasing-barnowl.txt \
     106    examples \
     107    marshal_types \
     108    perlglue.xs \
     109    scripts \
     110    stubgen.pl \
     111    typemap
    88112
    89113SUBDIRS = compat libfaim perl
  • README

    rbbd0cf1 r1c22155  
    1010following CPAN modules:
    1111
    12 AnyEvent::HTTP
    1312Facebook::Graph
    1413Net::Jabber
    1514Net::XMPP
    16 Ouch
    17 URI::Encode
    1815XML::Stream
    1916
     
    2421AnyEvent
    2522Class::Accessor
     23ExtUtils::Depends
    2624Glib
     25Module::Install
    2726PAR
    2827
     
    3029We plan to soon add targets to the Makefile to check for and install
    3130these for you.
     31
     32The Facebook module requires:
     33
     34Any::Moose
     35AnyEvent::HTTP
     36DateTime
     37DateTime::Format::Strptime
     38JSON
     39MIME::Base64::URLSafe
     40Ouch
     41URI
     42URI::Encode
    3243
    3344The IRC module requires:
     
    4051Authen::SASL::Perl
    4152IO::Socket::SSL
    42 Digest::SHA1
     53Digest::SHA
    4354
    4455The Twitter module requires:
  • aim.c

    rf271129 r8258ea5  
    707707{
    708708  aim_clientready(sess, fr->conn);
    709   owl_function_debugmsg("conninitdone_admin: initializtion done for admin connection");
     709  owl_function_debugmsg("conninitdone_admin: initialization done for admin connection");
    710710  return(1);
    711711}
     
    836836  params = va_arg(ap, struct aim_icbmparameters *);
    837837  va_end(ap);
    838  
    839   owl_function_debugmsg("faimtest_icbmparaminfo: ICBM Parameters: maxchannel = %d, default flags = 0x%08x, max msg len = %d, max sender evil = %f, max reciever evil = %f, min msg interval = %u",
     838
     839  owl_function_debugmsg("faimtest_icbmparaminfo: ICBM Parameters: maxchannel = %d, default flags = 0x%08x, max msg len = %d, max sender evil = %f, max receiver evil = %f, min msg interval = %u",
    840840                       params->maxchan, params->flags, params->maxmsglen, ((float)params->maxsenderwarn)/10.0, ((float)params->maxrecverwarn)/10.0, params->minmsginterval);
    841841     
  • barnowl-wrapper.in

    • Property mode changed from 100755 to 100644
    rf5f6ec0 ra223b6b  
    11#!/bin/sh
    22# This is a wrapper script to point BARNOWL_DATA_DIR at the source dir
    3 # if we're running from a build tree. barnowl.bin is the actual built
     3# if we're running from a build tree. bin/barnowl is the actual built
    44# binary.
    55
    6 SRCDIR=`dirname "${0}"`
    7 EXE="$0.bin"
     6EXE="@abs_builddir@/bin/$(basename "$0")"
    87
    98if test ! -x "$EXE"; then
     
    1211fi
    1312
    14 BARNOWL_DATA_DIR="$SRCDIR/perl/"
    15 BARNOWL_BIN_DIR="$SRCDIR/"
     13BARNOWL_DATA_DIR="@abs_srcdir@/perl"
     14BARNOWL_BIN_DIR="@abs_builddir@"
    1615export BARNOWL_DATA_DIR
    1716export BARNOWL_BIN_DIR
  • commands.c

    r39a531d ra38becd  
    479479
    480480  OWLCMD_ARGS("away", owl_command_away, OWL_CTX_INTERACTIVE,
    481               "Set, enable or disable both AIM and zephyr away messages",
     481              "Set, enable or disable all away messages",
    482482              "away [ on | off | toggle ]\n"
    483483              "away <message>",
    484               "Turn on or off the AIM and zephyr away message.  If\n"
     484              "Turn on or off all away messages.  If\n"
    485485              "'message' is specified turn them on with that message,\n"
    486486              "otherwise use the default.\n"
    487               "\n"
    488               "This command really just runs the 'aaway' and 'zaway'\n"
    489               "commands together\n"
    490487              "\n"
    491488              "SEE ALSO: aaway, zaway"),
     
    10331030  OWLCMD_ARGS_CTX("popless:start-search", owl_viewwin_command_start_search, OWL_CTX_POPLESS,
    10341031                  "starts a command line to search for particular string",
    1035                   "popless:start-search [-r] [inital-value]",
     1032                  "popless:start-search [-r] [initial-value]",
    10361033                  "Initializes the command-line to search for initial-value. If\n"
    10371034                  "-r is used, the search will be performed backwards.\n\n"
     
    15311528char *owl_command_away(int argc, const char *const *argv, const char *buff)
    15321529{
    1533   if ((argc==1) ||
    1534       ((argc==2) && !strcmp(argv[1], "on"))) {
     1530  bool away_off;
     1531  const char *message = NULL;
     1532
     1533  if (argc == 1 ||
     1534      (argc == 2 && !strcmp(argv[1], "on"))) {
     1535    away_off = false;
    15351536    owl_global_set_aaway_msg(&g, owl_global_get_aaway_msg_default(&g));
    15361537    owl_global_set_zaway_msg(&g, owl_global_get_zaway_msg_default(&g));
     1538  } else if (argc == 2 && !strcmp(argv[1], "off")) {
     1539    away_off = true;
     1540  } else if (argc == 2 && !strcmp(argv[1], "toggle")) {
     1541    away_off = owl_function_is_away();
     1542  } else {
     1543    away_off = false;
     1544    message = skiptokens(buff, 1);
     1545  }
     1546
     1547  if (away_off) {
     1548    owl_function_aaway_off();
     1549    owl_function_zaway_off();
     1550    owl_perlconfig_perl_call_norv("BarnOwl::Hooks::_away_off", 0, NULL);
     1551    owl_function_makemsg("Away messages off.");
     1552  } else if (message != NULL) {
     1553    owl_global_set_aaway_msg(&g, message);
     1554    owl_global_set_zaway_msg(&g, message);
    15371555    owl_function_aaway_on();
    15381556    owl_function_zaway_on();
     1557    owl_perlconfig_perl_call_norv("BarnOwl::Hooks::_away_on", 1, &message);
     1558    owl_function_makemsg("Away messages set (%s).", message);
     1559  } else {
     1560    owl_function_aaway_on();
     1561    owl_function_zaway_on();
     1562    owl_perlconfig_perl_call_norv("BarnOwl::Hooks::_away_on", 0, NULL);
    15391563    owl_function_makemsg("Away messages set.");
    1540     return NULL;
    1541   }
    1542 
    1543   if (argc==2 && !strcmp(argv[1], "off")) {
    1544     owl_function_aaway_off();
    1545     owl_function_zaway_off();
    1546     return NULL;
    1547   }
    1548 
    1549   if (argc==2 && !strcmp(argv[1], "toggle")) {
    1550     /* if either one is on, turn it off, otherwise toggle both (turn
    1551      *  them both on)
    1552      */
    1553     if (!owl_global_is_zaway(&g) && !owl_global_is_aaway(&g)) {
    1554       owl_function_aaway_toggle();
    1555       owl_function_zaway_toggle();
    1556       owl_function_makemsg("Away messages set.");
    1557     } else {
    1558       if (owl_global_is_zaway(&g)) owl_function_zaway_toggle();
    1559       if (owl_global_is_aaway(&g)) owl_function_aaway_toggle();
    1560       owl_function_makemsg("Away messages off.");
    1561     }
    1562     return NULL;
    1563   }
    1564 
    1565   buff = skiptokens(buff, 1);
    1566   owl_global_set_aaway_msg(&g, buff);
    1567   owl_global_set_zaway_msg(&g, buff);
    1568   owl_function_aaway_on();
    1569   owl_function_zaway_on();
    1570   owl_function_makemsg("Away messages set.");
     1564  }
     1565
    15711566  return NULL;
    15721567}
     
    16041599  if (v == NULL) {
    16051600    if (!silent) owl_function_error("Unknown variable '%s'", var);
    1606   } else if (requirebool && owl_variable_get_type(v) != OWL_VARIABLE_BOOL) {
     1601  } else if (requirebool && !v->takes_on_off) {
    16071602    if (!silent) owl_function_error("Variable '%s' is not a boolean", var);
    16081603  } else {
     
    16331628  if (v == NULL) {
    16341629    if (!silent) owl_function_error("Unknown variable '%s'", var);
    1635   } else if (owl_variable_get_type(v) != OWL_VARIABLE_BOOL) {
     1630  } else if (!v->takes_on_off) {
    16361631    if (!silent) owl_function_error("Variable '%s' is not a boolean", var);
    16371632  } else {
     
    21902185    if (!strcmp(argv[0], "-f")) {
    21912186      if (argc<2) {
    2192         owl_function_makemsg("Too few argments to the view command");
     2187        owl_function_makemsg("Too few arguments to the view command");
    21932188        return(NULL);
    21942189      }
     
    22022197    } else if (!strcmp(argv[0], "-s")) {
    22032198      if (argc<2) {
    2204         owl_function_makemsg("Too few argments to the view command");
     2199        owl_function_makemsg("Too few arguments to the view command");
    22052200        return(NULL);
    22062201      }
     
    22092204      argv+=2;
    22102205    } else {
    2211       owl_function_makemsg("Too few argments to the view command");
     2206      owl_function_makemsg("Too few arguments to the view command");
    22122207      return(NULL);
    22132208    }
  • compat/Makefile.am

    r12a6616 rb80bae0  
    11noinst_LIBRARIES = libcompat.a
    22
    3 libcompat_a_SOURCES =
     3libcompat_a_SOURCES = compat.h
    44libcompat_a_LIBADD = $(LIBOBJS)
  • compat/compat.h

    r4dde585 r6249a88f  
    22#define INC_BARNOWL_COMPAT_COMPAT_H
    33
    4 #include "../config.h"
     4#include <config.h>
    55
    66#include <stddef.h>
  • configure.ac

    r883502d r77dfeb1  
    11dnl Process this file with autoconf to produce a configure script.
    2 AC_INIT([BarnOwl],[1.9dev],[bug-barnowl@mit.edu])
    3 AM_INIT_AUTOMAKE([1.7.0 -Wall -Wno-portability foreign])
     2AC_INIT([BarnOwl],[1.10dev],[bug-barnowl@mit.edu])
     3AM_INIT_AUTOMAKE([1.7.0 foreign std-options -Wall -Wno-portability])
     4AM_MAINTAINER_MODE([enable])
    45m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
    56
     
    910AC_PROG_CC
    1011AC_PROG_CC_C99
     12AC_PROG_LN_S
     13
     14AC_ARG_WITH([zephyr-default-format],
     15    [AS_HELP_STRING([--with-zephyr-default-format],
     16                    [value for the default format zephyrgram field])],
     17    [
     18        case $withval in
     19            yes) withval='Config error: see http://mit.edu/df';;
     20            no) withval='';;
     21        esac
     22        zephyr_default_format=$withval
     23    ],
     24    [zephyr_default_format='Config error: see http://mit.edu/df'])
     25AC_DEFINE_UNQUOTED(
     26    [ZEPHYR_DEFAULT_FORMAT], ["$zephyr_default_format"],
     27    [Value for the default format zephyrgram field]
     28)
    1129
    1230AC_ARG_WITH([stack-protector],
     
    4159
    4260AS_IF([test "x$with_zephyr" != xno],
    43   [AS_IF([test "x$with_krb4" != "xno"],
     61  [have_krb4=no
     62
     63   AS_IF([test "x$with_krb4" != "xno"],
    4464   [AC_MSG_CHECKING([for Kerberos IV])
    4565    AS_IF([krb5-config krb4 --libs >/dev/null 2>&1],
    4666      [AC_MSG_RESULT([yes])
     67       have_krb4=yes
    4768       AC_DEFINE([HAVE_KERBEROS_IV], [1], [Define if you have kerberos IV])
    4869       AM_CFLAGS="${AM_CFLAGS} `krb5-config krb4 --cflags`"
     
    5172      [AC_MSG_RESULT([no])
    5273       AS_IF([test "x$with_krb4" = "xyes"],
    53              [AC_MSG_ERROR([Kerberos IV requested but not found])])
    54        PKG_CHECK_MODULES([LIBCRYPTO], [libcrypto])
    55        AM_CFLAGS="${AM_CFLAGS} ${LIBCRYPTO_CFLAGS}"
    56        LIBS="${LIBS} ${LIBCRYPTO_LIBS}"
    57      ])])
     74             [AC_MSG_ERROR([Kerberos IV requested but not found])])])])
     75
     76   AS_IF([test "x$have_krb4" != xyes],
     77     [PKG_CHECK_MODULES([LIBCRYPTO], [libcrypto],
     78        [AM_CFLAGS="${AM_CFLAGS} ${LIBCRYPTO_CFLAGS}"
     79         LIBS="${LIBS} ${LIBCRYPTO_LIBS}"
     80        ],
     81        [PKG_CHECK_MODULES([OPENSSL], [openssl],
     82           [AM_CFLAGS="${AM_CFLAGS} ${OPENSSL_CFLAGS}"
     83            LIBS="${LIBS} ${OPENSSL_LIBS}"
     84           ])])])
     85
    5886   AC_CHECK_LIB([zephyr], [ZGetSender],
    5987   [LIBS="$LIBS -lzephyr"
     
    90118dnl Find the location of perl XSUBPP
    91119AC_MSG_CHECKING(for the perl xsubpp precompiler)
    92 XSUBPPDIR="`(perl -MExtUtils::MakeMaker -e 'print ExtUtils::MakeMaker->new({NAME => qw(owl)})->tool_xsubpp;') | grep \^XSUBPPDIR | sed -e 's/XSUBPPDIR = //g;'`"
     120XSUBPPDIR="`cd "$srcdir" && perl -MExtUtils::MakeMaker -e 'print ExtUtils::MakeMaker->new({NAME => qw(owl)})->tool_xsubpp;' | grep \^XSUBPPDIR | sed -e 's/XSUBPPDIR = //g;'`"
    93121if test -n "${XSUBPPDIR}"; then
    94122   AC_MSG_RESULT(${XSUBPPDIR})
     
    113141AX_PROG_PERL_MODULES([Class::Accessor::Fast],,
    114142                     [AC_MSG_ERROR([cannot find perl module Class::Accessor::Fast.])])
     143AX_PROG_PERL_MODULES([ExtUtils::Depends],,
     144                     [AC_MSG_ERROR([cannot find perl module ExtUtils::Depends])])
    115145AX_PROG_PERL_MODULES([Glib],,
    116146                     [AC_MSG_ERROR([cannot find perl module Glib.])])
     147AX_PROG_PERL_MODULES([Module::Install::Base],,
     148                     [AC_MSG_ERROR([cannot find perl module Module::Install::Base])])
    117149AX_PROG_PERL_MODULES([PAR],,
    118150                     [AC_MSG_WARN([PAR.pm not found. Loadable modules will be disabled.])])
     
    129161   prefix="${ac_default_prefix}"
    130162fi
     163
     164dnl Add CFLAGS for glib-perl
     165GLIB_PERL_CFLAGS=`perl -MExtUtils::Depends -e 'my $e = ExtUtils::Depends->new("BarnOwl","Glib"); my %h = $e->get_makefile_vars; print $h{"INC"}'`
     166AC_MSG_NOTICE([Adding glib-perl CFLAGS ${GLIB_PERL_CFLAGS}])
     167AM_CFLAGS="${GLIB_PERL_CFLAGS} ${AM_CFLAGS}"
    131168
    132169dnl Checks for typedefs, structures, and compiler characteristics.
     
    150187dnl Define __EXTENSIONS__ for strcasecmp on Solaris.
    151188AM_CFLAGS="$AM_CFLAGS -D__EXTENSIONS__"
     189dnl Define _XOPEN_SOURCE_EXTENDED for some features in ncurses,
     190dnl including cchar_t.  This should not be necessary with
     191dnl _XOPEN_SOURCE=600, but some versions of ncurses
     192dnl apparently still need it.
     193AM_CFLAGS="$AM_CFLAGS -D_XOPEN_SOURCE_EXTENDED"
    152194
    153195AC_SUBST([AM_CFLAGS])
     
    168210AC_REPLACE_FUNCS([memrchr])
    169211
     212AC_SUBST([abs_builddir])
     213AC_SUBST([abs_srcdir])
     214
    170215AC_CONFIG_FILES([Makefile compat/Makefile libfaim/Makefile perl/Makefile perl/modules/Makefile])
    171216AC_OUTPUT
  • doc/releasing-barnowl.txt

    r5f08dbe rd995ff3  
    1616  - [ ] Do a locker build (See DOING A LOCKER BUILD)
    1717  - [ ] Update configure.ac on master to bump the version to 1.(N+1)dev
     18  - [ ] Add the barnowl-1.(N+1)dev git tag
    1819  - [ ] Push git git:
    1920   - [ ] The RC commit
    2021   - [ ] The configure.ac change on master
    2122   - [ ] A release-1.N branch pointing at the RC commit
     23   - [ ] the new git tags
     24  - [ ] Update debian/changelog on the launchpad build using `dch -v 1.(N+1)`
     25   - [ ] bzr branch lp:~barnowl/barnowl/packaging && cd packaging && dch -v 1.(N+1)
     26   - [ ] Add relevant changelog entries such as "New upstream release" or
     27         "Placeholder version number for daily builds."; fix your name and email
     28         if necessary
     29   - [ ] bzr commit && bzr push
    2230  - [ ] Copy tarball into /mit/barnowl/web_scripts/dist
    2331  - [ ] Send mail announcing the RC to barnowl-dev@mit.edu
     
    3139* DOING THE ACTUAL RELEASE
    3240  - [ ] Update the changelog and configure.ac for barnowl 1.N
     41  - [ ] Copy the changelog changes to the master branch
    3342  - [ ] run ./scripts/do-release
    3443  - [ ] Do the locker build
  • editwin.c

    r7803326 r8258ea5  
    619619
    620620  if (!g_utf8_validate(s, -1, NULL)) {
    621     owl_function_debugmsg("owl_editwin_insert_string: received non-utf-8 string.");
     621    owl_function_debugmsg("owl_editwin_insert_string: received non-UTF-8 string.");
    622622    return 0;
    623623  }
  • filter.c

    r30781f6 rc068c03  
    124124
    125125  op1 = owl_filter_parse_primitive_expression(argc-i, argv+i, &skip);
     126  if(!op1) goto err;
    126127  i += skip;
    127   if(!op1) goto err;
    128128
    129129  while(i < argc) {
  • filterproc.c

    r97cdbaf5 r7155955  
    1 #include "owl.h"
     1#include "filterproc.h"
    22#include <sys/wait.h>
     3#include <fcntl.h>
     4#include <glib.h>
    35#include <poll.h>
     6#include <string.h>
     7#include <unistd.h>
    48
    59/* Even in case of error, send_receive is responsible for closing wfd
     
    8185                                &child_pid, &child_stdin, &child_stdout, NULL,
    8286                                NULL)) {
     87    *out = NULL;
    8388    return 1;
    8489  }
  • functions.c

    rd199207 ra38becd  
    855855void owl_function_unsuball(void)
    856856{
    857   unsuball();
    858   owl_function_makemsg("Unsubscribed from all messages.");
     857  if (unsuball())
     858    owl_function_makemsg("Unsubscribed from all messages.");
    859859}
    860860
     
    871871void owl_function_loadsubs(const char *file)
    872872{
    873   int ret, ret2;
    874   const char *foo;
     873  int ret, ret2, ret3;
    875874  char *path;
    876875
     
    884883
    885884  /* for backwards compatibility for now */
    886   ret2=owl_zephyr_loaddefaultsubs();
     885  ret2 = owl_zephyr_loaddefaultsubs();
     886  ret3 = owl_zephyr_loadbarnowldefaultsubs();
    887887
    888888  if (!owl_context_is_interactive(owl_global_get_context(&g))) return;
    889889
    890   foo=file?file:"file";
    891   if (ret==0 && ret2==0) {
     890  if (ret == 0 && ret2 == 0 && ret3 == 0) {
    892891    if (!file) {
    893892      owl_function_makemsg("Subscribed to messages.");
     
    895894      owl_function_makemsg("Subscribed to messages from %s", file);
    896895    }
    897   } else if (ret==-1) {
    898     owl_function_error("Could not read %s", foo);
    899   } else {
     896  } else if (ret == -1) {
     897    owl_function_error("Could not read %s", file ? file : "file");
     898  } else if (ret2 == -1) {
    900899    owl_function_error("Error subscribing to messages");
     900  } else {
     901    owl_function_error("Error subscribing to instanced personals");
    901902  }
    902903}
     
    990991  /* owl_aim_set_awaymsg(""); */
    991992  owl_function_makemsg("AIM away off");
     993}
     994
     995bool owl_function_is_away(void)
     996{
     997  return owl_global_is_zaway(&g) ||
     998         owl_global_is_aaway(&g) ||
     999         owl_perlconfig_perl_call_bool("BarnOwl::Hooks::_get_is_away", 0, NULL);
    9921000}
    9931001
     
    21862194  f = owl_filter_new(argv[1], argc-2, argv+2);
    21872195  if (f == NULL) {
    2188     owl_function_error("Invalid filter");
     2196    owl_function_error("Invalid filter: %s", argv[1]);
    21892197    return false;
    21902198  }
  • global.c

    r219f52c r120dac7  
    99  const char *homedir;
    1010
     11#if !GLIB_CHECK_VERSION(2, 35, 0)
    1112  g_type_init();
     13#endif
     14#if !GLIB_CHECK_VERSION(2, 31, 0)
    1215  g_thread_init(NULL);
     16#endif
    1317
    1418  owl_select_init();
     
    5256  g->starttime=time(NULL); /* assumes we call init only a start time */
    5357  g->lastinputtime=g->starttime;
     58  g->last_wakeup_time = g->starttime;
    5459  g->newmsgproc_pid=0;
    5560 
     
    100105
    101106  g->interrupt_count = 0;
     107#if GLIB_CHECK_VERSION(2, 31, 0)
     108  g_mutex_init(&g->interrupt_lock);
     109#else
    102110  g->interrupt_lock = g_mutex_new();
     111#endif
    103112}
    104113
     
    476485}
    477486
     487void owl_global_wakeup(owl_global *g)
     488{
     489  if (time(NULL) - g->last_wakeup_time >= 1) {
     490    g_free(owl_perlconfig_execute("BarnOwl::Hooks::_wakeup()"));
     491    g->last_wakeup_time = time(NULL);
     492  }
     493}
     494
    478495/* viewwin */
    479496
     
    841858  } filters[] = {
    842859    { "personal",
    843       "isprivate ^true$ and ( not type ^zephyr$ or ( class ^message  ) )" },
     860      "isprivate ^true$ and ( not type ^zephyr$ or ( class ^message$ ) )" },
    844861    { "trash",
    845862      "class ^mail$ or opcode ^ping$ or type ^admin$ or ( not login ^none$ )" },
     
    848865    { "auto", "opcode ^auto$" },
    849866    { "login", "not login ^none$" },
    850     { "reply-lockout", "class ^mail$" },
     867    { "reply-lockout", "class ^mail$ or class ^filsrv$" },
    851868    { "out", "direction ^out$" },
    852869    { "aim", "type ^aim$" },
     
    899916}
    900917
     918static GMutex *owl_global_get_interrupt_lock(owl_global *g)
     919{
     920#if GLIB_CHECK_VERSION(2, 31, 0)
     921  return &g->interrupt_lock;
     922#else
     923  return g->interrupt_lock;
     924#endif
     925}
     926
    901927void owl_global_add_interrupt(owl_global *g) {
    902928  /* TODO: This can almost certainly be done with atomic
    903929   * operations. Whatever. */
    904   g_mutex_lock(g->interrupt_lock);
     930  g_mutex_lock(owl_global_get_interrupt_lock(g));
    905931  g->interrupt_count++;
    906   g_mutex_unlock(g->interrupt_lock);
     932  g_mutex_unlock(owl_global_get_interrupt_lock(g));
    907933}
    908934
    909935bool owl_global_take_interrupt(owl_global *g) {
    910936  bool ans = false;
    911   g_mutex_lock(g->interrupt_lock);
     937  g_mutex_lock(owl_global_get_interrupt_lock(g));
    912938  if (g->interrupt_count > 0) {
    913939    ans = true;
    914940    g->interrupt_count--;
    915941  }
    916   g_mutex_unlock(g->interrupt_lock);
     942  g_mutex_unlock(owl_global_get_interrupt_lock(g));
    917943  return ans;
    918944}
  • help.c

    rf271129 r8258ea5  
    7373     "    : , M-x       Enter command mode\n"
    7474     "\n"
    75      "    /             Foward search\n"
     75     "    /             Forward search\n"
    7676     "    ?             Reverse search\n"
    7777     "\n\n"
     
    107107     "    unsuball      Unsubscribe from all zephyr classes\n"
    108108     "    load-subs     Load zephyr subscriptions from a file\n"
    109      "    zpunt         Supress messages from a zephyr triplet\n"
     109     "    zpunt         Suppress messages from a zephyr triplet\n"
    110110     "    zlog          Send a login or logout notification\n"
    111111     "    zlist         Print a list of zephyr buddies logged in\n"
  • libfaim/Makefile.am

    r215c119 rb80bae0  
    1313libfaim_a_CPPFLAGS = -DAIM_BUILDDATE=\"x\" -DAIM_BUILDTIME=\"x\" \
    1414                     -I${top_srcdir}/libfaim
     15
     16EXTRA_DIST = oscar.c
  • logging.c

    rf271129 r0792d99  
    429429static gpointer owl_log_thread_func(gpointer data)
    430430{
    431   log_context = g_main_context_new();
    432431  log_loop = g_main_loop_new(log_context, FALSE);
    433432  g_main_loop_run(log_loop);
     
    437436void owl_log_init(void)
    438437{
     438  log_context = g_main_context_new();
     439#if GLIB_CHECK_VERSION(2, 31, 0)
     440  logging_thread = g_thread_new("logging",
     441                                owl_log_thread_func,
     442                                NULL);
     443#else
    439444  GError *error = NULL;
    440445  logging_thread = g_thread_create(owl_log_thread_func,
     
    448453    exit(1);
    449454  }
     455#endif
    450456 
    451457}
  • m4/ax_cflags_warn_all.m4

    r378ede7 re9b4a2c  
    2525#    - $3 action-if-found : add value to shellvariable
    2626#    - $4 action-if-not-found : nothing
     27#
     28#   NOTE: These macros depend on AX_APPEND_FLAG.
    2729#
    2830# LICENSE
     
    5759#   exception to the GPL to apply to your modified version as well.
    5860
    59 #serial 10
     61#serial 14
    6062
    61 AC_DEFUN([AX_CFLAGS_WARN_ALL],[dnl
    62 AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl
    63 AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_warn_all])dnl
     63AC_DEFUN([AX_FLAGS_WARN_ALL],[dnl
     64AS_VAR_PUSHDEF([FLAGS],[_AC_LANG_PREFIX[]FLAGS])dnl
     65AS_VAR_PUSHDEF([VAR],[ac_cv_[]_AC_LANG_ABBREV[]flags_warn_all])dnl
    6466AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings],
    6567VAR,[VAR="no, unknown"
    66  AC_LANG_PUSH([C])
    67  ac_save_[]FLAGS="$[]FLAGS"
    68 for ac_arg dnl
    69 in "-pedantic  % -Wall"       dnl   GCC
    70    "-xstrconst % -v"          dnl Solaris C
    71    "-std1      % -verbose -w0 -warnprotos" dnl Digital Unix
    72    "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX
    73    "-ansi -ansiE % -fullwarn" dnl IRIX
    74    "+ESlit     % +w1"         dnl HP-UX C
    75    "-Xc        % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10)
    76    "-h conform % -h msglevel 2" dnl Cray C (Unicos)
    77    #
    78 do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
    79    AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
    80                      [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
    81 done
    82  FLAGS="$ac_save_[]FLAGS"
    83  AC_LANG_POP([C])
    84 ])
    85 case ".$VAR" in
    86      .ok|.ok,*) m4_ifvaln($3,$3) ;;
    87    .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[
    88         AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])
    89                       m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;;
    90    *) m4_ifvaln($3,$3,[
    91    if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
    92    then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR])
    93    else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"])
    94                       m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"
    95    fi ]) ;;
    96 esac
    97 AS_VAR_POPDEF([VAR])dnl
    98 AS_VAR_POPDEF([FLAGS])dnl
    99 ])
    100 
    101 dnl the only difference - the LANG selection... and the default FLAGS
    102 
    103 AC_DEFUN([AX_CXXFLAGS_WARN_ALL],[dnl
    104 AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl
    105 AS_VAR_PUSHDEF([VAR],[ax_cv_cxxflags_warn_all])dnl
    106 AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings],
    107 VAR,[VAR="no, unknown"
    108  AC_LANG_PUSH([C++])
    109  ac_save_[]FLAGS="$[]FLAGS"
    110 for ac_arg dnl
    111 in "-pedantic  % -Wall"       dnl   GCC
    112    "-xstrconst % -v"          dnl Solaris C
    113    "-std1      % -verbose -w0 -warnprotos" dnl Digital Unix
    114    "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX
    115    "-ansi -ansiE % -fullwarn" dnl IRIX
    116    "+ESlit     % +w1"         dnl HP-UX C
    117    "-Xc        % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10)
    118    "-h conform % -h msglevel 2" dnl Cray C (Unicos)
    119    #
    120 do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
    121    AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
    122                      [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
    123 done
    124  FLAGS="$ac_save_[]FLAGS"
    125  AC_LANG_POP([C++])
    126 ])
    127 case ".$VAR" in
    128      .ok|.ok,*) m4_ifvaln($3,$3) ;;
    129    .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[
    130         AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])
    131                       m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;;
    132    *) m4_ifvaln($3,$3,[
    133    if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
    134    then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR])
    135    else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"])
    136                       m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"
    137    fi ]) ;;
    138 esac
    139 AS_VAR_POPDEF([VAR])dnl
    140 AS_VAR_POPDEF([FLAGS])dnl
    141 ])
    142 
    143 dnl the only difference - the LANG selection... and the default FLAGS
    144 
    145 AC_DEFUN([AX_FCFLAGS_WARN_ALL],[dnl
    146 AS_VAR_PUSHDEF([FLAGS],[FCFLAGS])dnl
    147 AS_VAR_PUSHDEF([VAR],[ax_cv_fcflags_warn_all])dnl
    148 AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings],
    149 VAR,[VAR="no, unknown"
    150  AC_LANG_PUSH([Fortran])
    151  ac_save_[]FLAGS="$[]FLAGS"
     68ac_save_[]FLAGS="$[]FLAGS"
    15269for ac_arg dnl
    15370in "-warn all  % -warn all"   dnl Intel
     
    16582                     [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
    16683done
    167  FLAGS="$ac_save_[]FLAGS"
    168  AC_LANG_POP([Fortran])
     84FLAGS="$ac_save_[]FLAGS"
    16985])
     86AS_VAR_POPDEF([FLAGS])dnl
     87AC_REQUIRE([AX_APPEND_FLAG])
    17088case ".$VAR" in
    17189     .ok|.ok,*) m4_ifvaln($3,$3) ;;
    172    .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[
    173         AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])
    174                       m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;;
    175    *) m4_ifvaln($3,$3,[
    176    if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
    177    then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR])
    178    else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"])
    179                       m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"
    180    fi ]) ;;
     90   .|.no|.no,*) m4_default($4,[m4_ifval($2,[AX_APPEND_FLAG([$2], [$1])])]) ;;
     91   *) m4_default($3,[AX_APPEND_FLAG([$VAR], [$1])]) ;;
    18192esac
    18293AS_VAR_POPDEF([VAR])dnl
    183 AS_VAR_POPDEF([FLAGS])dnl
    184 ])
    185 
     94])dnl AX_FLAGS_WARN_ALL
    18695dnl  implementation tactics:
    18796dnl   the for-argument contains a list of options. The first part of
     
    194103dnl   delimiter. A non-option comment can be given after "%%" marks
    195104dnl   which will be shown but not added to the respective C/CXXFLAGS.
     105
     106AC_DEFUN([AX_CFLAGS_WARN_ALL],[dnl
     107AC_LANG_PUSH([C])
     108AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4])
     109AC_LANG_POP([C])
     110])
     111
     112AC_DEFUN([AX_CXXFLAGS_WARN_ALL],[dnl
     113AC_LANG_PUSH([C++])
     114AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4])
     115AC_LANG_POP([C++])
     116])
     117
     118AC_DEFUN([AX_FCFLAGS_WARN_ALL],[dnl
     119AC_LANG_PUSH([Fortran])
     120AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4])
     121AC_LANG_POP([Fortran])
     122])
  • m4/pkg.m4

    r650fb2c r13a39ae8  
    158158fi[]dnl
    159159])# PKG_CHECK_MODULES
     160
     161
     162# PKG_INSTALLDIR(DIRECTORY)
     163# -------------------------
     164# Substitutes the variable pkgconfigdir as the location where a module
     165# should install pkg-config .pc files. By default the directory is
     166# $libdir/pkgconfig, but the default can be changed by passing
     167# DIRECTORY. The user can override through the --with-pkgconfigdir
     168# parameter.
     169AC_DEFUN([PKG_INSTALLDIR],
     170[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
     171m4_pushdef([pkg_description],
     172    [pkg-config installation directory @<:@]pkg_default[@:>@])
     173AC_ARG_WITH([pkgconfigdir],
     174    [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
     175    [with_pkgconfigdir=]pkg_default)
     176AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
     177m4_popdef([pkg_default])
     178m4_popdef([pkg_description])
     179]) dnl PKG_INSTALLDIR
     180
     181
     182# PKG_NOARCH_INSTALLDIR(DIRECTORY)
     183# -------------------------
     184# Substitutes the variable noarch_pkgconfigdir as the location where a
     185# module should install arch-independent pkg-config .pc files. By
     186# default the directory is $datadir/pkgconfig, but the default can be
     187# changed by passing DIRECTORY. The user can override through the
     188# --with-noarch-pkgconfigdir parameter.
     189AC_DEFUN([PKG_NOARCH_INSTALLDIR],
     190[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
     191m4_pushdef([pkg_description],
     192    [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
     193AC_ARG_WITH([noarch-pkgconfigdir],
     194    [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
     195    [with_noarch_pkgconfigdir=]pkg_default)
     196AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
     197m4_popdef([pkg_default])
     198m4_popdef([pkg_description])
     199]) dnl PKG_NOARCH_INSTALLDIR
     200
     201
     202# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
     203# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
     204# -------------------------------------------
     205# Retrieves the value of the pkg-config variable for the given module.
     206AC_DEFUN([PKG_CHECK_VAR],
     207[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
     208AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
     209
     210_PKG_CONFIG([$1], [variable="][$3]["], [$2])
     211AS_VAR_COPY([$1], [pkg_cv_][$1])
     212
     213AS_VAR_IF([$1], [""], [$5], [$4])dnl
     214])# PKG_CHECK_VAR
  • message.c

    r97cdbaf5 r2354e9a  
    881881      NULL
    882882    };
    883     char *out;
     883    char *out = NULL;
    884884    int rv;
    885885    int status;
     
    898898      }
    899899      owl_message_set_body(m, out);
    900       g_free(out);
    901     } else if(out) {
    902       g_free(out);
    903     }
     900    } else {
     901      /* Replace the opcode. Otherwise the UI and other bits of code think the
     902       * message was encrypted. */
     903      owl_message_set_opcode(m, "failed-decrypt");
     904    }
     905    g_free(out);
    904906  }
    905907
  • owl.c

    r8135737 r120dac7  
    1212#include <sys/stat.h>
    1313#include <locale.h>
     14#include <unistd.h>
    1415
    1516#if OWL_STDERR_REDIR
     
    3334} owl_options;
    3435
    35 void usage(void)
     36void usage(FILE *file)
    3637{
    37   fprintf(stderr, "Barnowl version %s\n", OWL_VERSION_STRING);
    38   fprintf(stderr, "Usage: barnowl [-n] [-d] [-D] [-v] [-h] [-c <configfile>] [-s <confdir>] [-t <ttyname>]\n");
    39   fprintf(stderr, "  -n,--no-subs        don't load zephyr subscriptions\n");
    40   fprintf(stderr, "  -d,--debug          enable debugging\n");
    41   fprintf(stderr, "  -v,--version        print the Barnowl version number and exit\n");
    42   fprintf(stderr, "  -h,--help           print this help message\n");
    43   fprintf(stderr, "  -s,--config-dir     specify an alternate config dir (default ~/.owl)\n");
    44   fprintf(stderr, "  -c,--config-file    specify an alternate config file (default ~/.owl/init.pl)\n");
    45   fprintf(stderr, "  -t,--tty            set the tty name\n");
     38  fprintf(file, "Barnowl version %s\n", OWL_VERSION_STRING);
     39  fprintf(file, "Usage: barnowl [-n] [-d] [-D] [-v] [-h] [-c <configfile>] [-s <confdir>] [-t <ttyname>]\n");
     40  fprintf(file, "  -n,--no-subs        don't load zephyr subscriptions\n");
     41  fprintf(file, "  -d,--debug          enable debugging\n");
     42  fprintf(file, "  -v,--version        print the Barnowl version number and exit\n");
     43  fprintf(file, "  -h,--help           print this help message\n");
     44  fprintf(file, "  -s,--config-dir     specify an alternate config dir (default ~/.owl)\n");
     45  fprintf(file, "  -c,--config-file    specify an alternate config file (default ~/.owl/init.pl)\n");
     46  fprintf(file, "  -t,--tty            set the tty name\n");
    4647}
    4748
     
    8283      exit(0);
    8384    case 'h':
     85      usage(stdout);
     86      exit(0);
    8487    default:
    85       usage();
     88      usage(stderr);
    8689      exit(1);
    8790    }
     
    286289
    287290  owl_global_set_lastinputtime(&g, time(NULL));
     291  owl_global_wakeup(&g);
    288292  ret = owl_keyhandler_process(owl_global_get_keyhandler(&g), j);
    289293  if (ret!=0 && ret!=1) {
     
    427431  if (0 != pipe(pipefds)) {
    428432    perror("pipe");
    429     owl_function_debugmsg("stderr_replace: pipe FAILED\n");
     433    owl_function_debugmsg("stderr_replace: pipe FAILED");
    430434    return -1;
    431435  }
    432     owl_function_debugmsg("stderr_replace: pipe: %d,%d\n", pipefds[0], pipefds[1]);
    433   if (-1 == dup2(pipefds[1], 2 /*stderr*/)) {
    434     owl_function_debugmsg("stderr_replace: dup2 FAILED (%s)\n", strerror(errno));
     436    owl_function_debugmsg("stderr_replace: pipe: %d,%d", pipefds[0], pipefds[1]);
     437  if (-1 == dup2(pipefds[1], STDERR_FILENO)) {
     438    owl_function_debugmsg("stderr_replace: dup2 FAILED (%s)", strerror(errno));
    435439    perror("dup2");
    436440    return -1;
     
    514518#if OWL_STDERR_REDIR
    515519  /* Do this only after we've started curses up... */
    516   owl_function_debugmsg("startup: doing stderr redirection");
    517   channel = g_io_channel_unix_new(stderr_replace());
    518   g_io_add_watch(channel, G_IO_IN | G_IO_HUP | G_IO_ERR, &stderr_redirect_handler, NULL);
    519   g_io_channel_unref(channel);
     520  if (isatty(STDERR_FILENO)) {
     521    owl_function_debugmsg("startup: doing stderr redirection");
     522    channel = g_io_channel_unix_new(stderr_replace());
     523    g_io_add_watch(channel, G_IO_IN | G_IO_HUP | G_IO_ERR, &stderr_redirect_handler, NULL);
     524    g_io_channel_unref(channel);
     525  }
    520526#endif
    521527
  • owl.h

    r219f52c r120dac7  
    1010#define INC_BARNOWL_OWL_H
    1111
    12 #include "config.h"
     12#include <config.h>
    1313
    1414#include "compat/compat.h"
     
    4747/* Perl and curses don't play nice. */
    4848#ifdef OWL_PERL
    49 typedef void WINDOW;
    50 typedef void PANEL;
     49typedef struct _owl_fake_WINDOW WINDOW;
     50typedef struct _owl_fake_PANEL PANEL;
    5151/* logout is defined in FreeBSD. */
    5252#define logout logout_
     
    5757#include "XSUB.h"
    5858#else
    59 typedef void SV;
    60 typedef void AV;
    61 typedef void HV;
     59typedef struct _owl_fake_SV SV;
     60typedef struct _owl_fake_AV AV;
     61typedef struct _owl_fake_HV HV;
    6262#endif
    6363
     
    235235  char *name;
    236236  int   type;  /* OWL_VARIABLE_* */
    237   void *pval_default;  /* for types other and string */
    238   int   ival_default;  /* for types int and bool     */
    239   const char *validsettings;    /* documentation of valid settings */
     237  char *default_str;            /* the default value as a string */
     238  char *validsettings;          /* documentation of valid settings */
    240239  char *summary;                /* summary of usage */
    241240  char *description;            /* detailed description */
    242   void *val;                    /* current value */
    243   int  (*validate_fn)(const struct _owl_variable *v, const void *newval);
     241  bool takes_on_off;            /* allow passing on/off in argument-less set/unset */
     242  GClosure *set_fromstring_fn;
     243                                /* sets the variable to a value
     244                                 * of the appropriate type.
     245                                 * unless documented, this
     246                                 * should make a copy.
     247                                 * returns 0 on success. */
     248  GClosure *get_tostring_fn;
     249                                /* converts val to a string;
     250                                 * caller must free the result */
     251
     252  /* These are only valid for OWL_VARIABLE_{INT,BOOL,STRING} */
     253  GValue val;                   /* current value, if default get_fn/set_fn */
     254
     255  GCallback get_fn;
     256                                /* returns a reference to the current value.
     257                                 * WARNING:  this approach is hard to make
     258                                 * thread-safe... */
     259  GCallback validate_fn;
    244260                                /* returns 1 if newval is valid */
    245   int  (*set_fn)(struct _owl_variable *v, const void *newval);
     261  GCallback set_fn;
    246262                                /* sets the variable to a value
    247                                  * of the appropriate type.
    248                                  * unless documented, this
    249                                  * should make a copy.
    250                                  * returns 0 on success. */
    251   int  (*set_fromstring_fn)(struct _owl_variable *v, const char *newval);
    252                                 /* sets the variable to a value
    253                                  * of the appropriate type.
    254                                  * unless documented, this
    255                                  * should make a copy.
    256                                  * returns 0 on success. */
    257   const void *(*get_fn)(const struct _owl_variable *v);
    258                                 /* returns a reference to the current value.
    259                                  * WARNING:  this approach is hard to make
    260                                  * thread-safe... */
    261   CALLER_OWN char *(*get_tostring_fn)(const struct _owl_variable *v, const void *val);
    262                                 /* converts val to a string;
    263                                  * caller must free the result */
    264   void (*delete_fn)(struct _owl_variable *v);
    265                                 /* frees val as needed */
     263                                 * of the appropriate type.
     264                                 * unless documented, this
     265                                 * should make a copy.
     266                                 * returns 0 on success. */
    266267} owl_variable;
     268
    267269
    268270typedef struct _owl_input {
     
    569571  time_t starttime;
    570572  time_t lastinputtime;
     573  time_t last_wakeup_time;
    571574  char *startupargs;
    572575  int nextmsgid;
     
    596599  char *kill_buffer;
    597600  int interrupt_count;
     601#if GLIB_CHECK_VERSION(2, 31, 0)
     602  GMutex interrupt_lock;
     603#else
    598604  GMutex *interrupt_lock;
     605#endif
    599606} owl_global;
    600607
     
    602609extern owl_global g;
    603610
    604 #include "owl_prototypes.h"
     611#include <owl_prototypes.h>
    605612
    606613/* These were missing from the Zephyr includes before Zephyr 3. */
     
    610617#endif
    611618
     619/* We have to dynamically bind these ourselves */
     620extern gboolean (*gvalue_from_sv) (GValue * value, SV * sv);
     621extern SV * (*sv_from_gvalue) (const GValue * value);
     622extern GClosure * (*perl_closure_new) (SV * callback, SV * data, gboolean swap);
     623
     624
    612625#endif /* INC_BARNOWL_OWL_H */
  • owl_perl.h

    rf271129 r92ffd89  
    44#include <stdio.h>
    55
    6 #define OWL_PERL_VOID_CALL (void)POPs;
     6/*
     7 * This macro defines a convenience wrapper around the boilerplate
     8 * of pushing char * arguments on to the stack for perl calling.
     9 *
     10 * Arguments are
     11 * * i     - the counter variable to use, which must be declared prior
     12 *           to calling this macro
     13 * * argc  - the number of arguments
     14 * * argv  - an array of char*s, of length at least argc; the arguments
     15 *           to push on to the stack
     16 */
     17#define OWL_PERL_PUSH_ARGS(i, argc, argv) { \
     18  for (i = 0; i < argc; i++) { \
     19    XPUSHs(sv_2mortal(owl_new_sv(argv[i]))); \
     20  } \
     21}
    722
    823/*
    924 * This macro defines a convenience wrapper around the boilerplate of
    10  * calling a method on a perl object (SV*) from C.
     25 * the perlcall methods.
    1126 *
    1227 * Arguments are
    13  * * obj    - the SV* to call the method on
    14  * * meth   - a char* method name
    15  * * args   - a code block responsible for pushing args (other than the object)
    16  * * err    - a string with a %s format specifier to log in case of error
    17  * * fatalp - if true, perl errors terminate BarnOwl
    18  * * ret    - a code block executed if the call succeeded
     28 * * call       - the line of code to make the perl call
     29 * * args       - a code block responsible for pushing args
     30 * * err        - a string with a %s format specifier to log in case of error
     31 * * fatalp     - if true, perl errors terminate BarnOwl
     32 * * discardret - should be true if no return is expected
     33 *                (if the call is passed the flag G_DISCARD or G_VOID)
     34 * * ret        - a code block executed if the call succeeded
    1935 *
    2036 * See also: `perldoc perlcall', `perldoc perlapi'
    2137 */
    22 #define OWL_PERL_CALL_METHOD(obj, meth, args, err, fatalp, ret) { \
    23     int count; \
    24     dSP; \
    25     ENTER; \
    26     SAVETMPS; \
    27     PUSHMARK(SP); \
    28     XPUSHs(obj); \
    29     {args} \
    30     PUTBACK; \
    31     \
    32     count = call_method(meth, G_SCALAR|G_EVAL); \
    33     \
    34     SPAGAIN; \
    35     \
    36     if(count != 1) { \
    37       fprintf(stderr, "perl returned wrong count: %d\n", count); \
    38       abort();                                                   \
     38#define OWL_PERL_CALL(call, args, err, fatalp, discardret, ret) { \
     39  int count; \
     40  dSP; \
     41  \
     42  ENTER; \
     43  SAVETMPS; \
     44  \
     45  PUSHMARK(SP); \
     46  {args} \
     47  PUTBACK; \
     48  \
     49  count = call; \
     50  \
     51  SPAGAIN; \
     52  \
     53  if (!discardret && count != 1) { \
     54    croak("Perl returned wrong count: %d\n", count); \
     55  } \
     56  \
     57  if (SvTRUE(ERRSV)) { \
     58    if (fatalp) { \
     59      fprintf(stderr, err, SvPV_nolen(ERRSV)); \
     60      exit(-1); \
     61    } else { \
     62      owl_function_error(err, SvPV_nolen(ERRSV)); \
     63      if (!discardret) (void)POPs; \
     64      sv_setsv(ERRSV, &PL_sv_undef); \
    3965    } \
    40     if (SvTRUE(ERRSV)) { \
    41       if(fatalp) { \
    42         printf(err, SvPV_nolen(ERRSV)); \
    43         exit(-1); \
    44       } else { \
    45         owl_function_error(err, SvPV_nolen(ERRSV)); \
    46         (void)POPs; \
    47         sv_setsv(ERRSV, &PL_sv_undef); \
    48       } \
    49     } else { \
    50       ret; \
    51     } \
    52     PUTBACK; \
    53     FREETMPS; \
    54     LEAVE; \
     66  } else if (!discardret) { \
     67    ret; \
     68  } \
     69  PUTBACK; \
     70  FREETMPS; \
     71  LEAVE; \
    5572}
    5673
  • perl/Makefile.am

    r10557e6 ra870319  
    11SUBDIRS = modules
     2nobase_dist_pkgdata_DATA = \
     3        lib/BarnOwl.pm \
     4        lib/BarnOwl/Complete/AIM.pm \
     5        lib/BarnOwl/Complete/Client.pm \
     6        lib/BarnOwl/Complete/Filter.pm \
     7        lib/BarnOwl/Complete/Zephyr.pm \
     8        lib/BarnOwl/Completion.pm \
     9        lib/BarnOwl/Completion/Context.pm \
     10        lib/BarnOwl/Completion/Util.pm \
     11        lib/BarnOwl/Editwin.pm \
     12        lib/BarnOwl/Help.pm \
     13        lib/BarnOwl/Hook.pm \
     14        lib/BarnOwl/Hooks.pm \
     15        lib/BarnOwl/MainLoopCompatHook.pm \
     16        lib/BarnOwl/Message.pm \
     17        lib/BarnOwl/Message/AIM.pm \
     18        lib/BarnOwl/Message/Admin.pm \
     19        lib/BarnOwl/Message/Generic.pm \
     20        lib/BarnOwl/Message/Loopback.pm \
     21        lib/BarnOwl/Message/Zephyr.pm \
     22        lib/BarnOwl/ModuleLoader.pm \
     23        lib/BarnOwl/Parse.pm \
     24        lib/BarnOwl/Style.pm \
     25        lib/BarnOwl/Style/Basic.pm \
     26        lib/BarnOwl/Style/Default.pm \
     27        lib/BarnOwl/Style/Legacy.pm \
     28        lib/BarnOwl/Style/OneLine.pm \
     29        lib/BarnOwl/Timer.pm \
     30        lib/BarnOwl/Zephyr.pm \
     31        lib/Module/Install/BarnOwl.pm
  • perl/lib/BarnOwl.pm

    r8135737 recd4edf  
    55
    66use base qw(Exporter);
    7 our @EXPORT_OK = qw(command getcurmsg getnumcols getidletime
     7our @EXPORT_OK = qw(command getcurmsg getnumcols getnumlines getidletime
     8                    register_idle_watcher unregister_idle_watcher
    89                    zephyr_getsender zephyr_getrealm zephyr_zwrite
    910                    zephyr_stylestrip zephyr_smartstrip_user zephyr_getsubs
     
    1415                    error debug
    1516                    create_style getnumcolors wordwrap
     17                    message_matches_filter
    1618                    add_dispatch remove_dispatch
    1719                    add_io_dispatch remove_io_dispatch
    1820                    new_command
    1921                    new_variable_int new_variable_bool new_variable_string
     22                    new_variable_enum
    2023                    quote redisplay);
    2124our %EXPORT_TAGS = (all => \@EXPORT_OK);
     
    4447
    4548use List::Util qw(max);
     49use Tie::RefHash;
    4650
    4751=head1 NAME
     
    9296Sends a zephyr programmatically. C<COMMAND> should be a C<zwrite>
    9397command line, and C<MESSAGE> is the zephyr body to send.
     98
     99=cut
     100
     101sub zephyr_zwrite {
     102    my ($command, $message) = @_;
     103    my $ret = BarnOwl::Internal::zephyr_zwrite($command, $message);
     104    die "Error sending zephyr" unless $ret == 0;
     105}
    94106
    95107=head2 ztext_stylestrip STRING
     
    230242
    231243Returns the number of colors this BarnOwl is capable of displaying
     244
     245=head2 message_matches_filter MESSAGE FILTER_NAME [QUIET = 0]
     246
     247Returns 1 if C<FILTER_NAME> is the name of a valid filter, and
     248C<MESSAGE> matches that filter.  Returns 0 otherwise.  If
     249C<QUIET> is false, this method displays an error message if
     250if C<FILTER_NAME> does not name a valid filter.
    232251
    233252=head2 add_dispatch FD CALLBACK
     
    394413=head2 new_variable_string NAME [{ARGS}]
    395414
    396 Add a new owl variable, either an int, a bool, or a string, with the
     415=head2 new_variable_enum NAME [{ARGS}]
     416
     417Add a new owl variable, either an int, a bool, a string, or an enum with the
    397418specified name.
    398419
    399 ARGS can optionally contain the following keys:
     420For new_variable_enum, ARGS is required to contain a validsettings key pointing
     421to an array reference. For all four, it can optionally contain the following
     422keys:
    400423
    401424=over 4
     
    415438=back
    416439
     440In addition, new_variable_string optionally accepts a string validsettings
     441parameter, in case people want to set it to "<path>".
     442
    417443=cut
    418444
    419445sub new_variable_int {
    420     unshift @_, \&BarnOwl::Internal::new_variable_int, 0;
    421     goto \&_new_variable;
     446    my ($name, $args) = @_;
     447    my $storage = defined($args->{default}) ? $args->{default} : 0;
     448    BarnOwl::new_variable_full($name, {
     449            %{$args},
     450            get_tostring => sub { "$storage" },
     451            set_fromstring => sub {
     452                die "Expected integer" unless $_[0] =~ /^-?[0-9]+$/;
     453                $storage = 0 + $_[0];
     454            },
     455            validsettings => "<int>",
     456            takes_on_off => 0,
     457        });
    422458}
    423459
    424460sub new_variable_bool {
    425     unshift @_, \&BarnOwl::Internal::new_variable_bool, 0;
    426     goto \&_new_variable;
     461    my ($name, $args) = @_;
     462    my $storage = defined($args->{default}) ? $args->{default} : 0;
     463    BarnOwl::new_variable_full($name, {
     464            %{$args},
     465            get_tostring => sub { $storage ? "on" : "off" },
     466            set_fromstring => sub {
     467                die "Valid settings are on/off" unless $_[0] eq "on" || $_[0] eq "off";
     468                $storage = $_[0] eq "on";
     469            },
     470            validsettings => "on,off",
     471            takes_on_off => 1,
     472        });
    427473}
    428474
    429475sub new_variable_string {
    430     unshift @_, \&BarnOwl::Internal::new_variable_string, "";
    431     goto \&_new_variable;
    432 }
    433 
    434 sub _new_variable {
    435     my $func = shift;
    436     my $default_default = shift;
     476    my ($name, $args) = @_;
     477    my $storage = defined($args->{default}) ? $args->{default} : "";
     478    BarnOwl::new_variable_full($name, {
     479            # Allow people to override this one if they /reaaally/ want to for
     480            # some reason. Though we still reserve the right to interpret this
     481            # value in interesting ways for tab-completion purposes.
     482            validsettings => "<string>",
     483            %{$args},
     484            get_tostring => sub { $storage },
     485            set_fromstring => sub { $storage = $_[0]; },
     486            takes_on_off => 0,
     487        });
     488}
     489
     490sub new_variable_enum {
     491    my ($name, $args) = @_;
     492
     493    # Gather the valid settings.
     494    die "validsettings is required" unless defined($args->{validsettings});
     495    my %valid;
     496    map { $valid{$_} = 1 } @{$args->{validsettings}};
     497
     498    my $storage = (defined($args->{default}) ?
     499                   $args->{default} :
     500                   $args->{validsettings}->[0]);
     501    BarnOwl::new_variable_full($name, {
     502            %{$args},
     503            get_tostring => sub { $storage },
     504            set_fromstring => sub {
     505                die "Invalid input" unless $valid{$_[0]};
     506                $storage = $_[0];
     507            },
     508            validsettings => join(",", @{$args->{validsettings}})
     509        });
     510}
     511
     512=head2 new_variable_full NAME {ARGS}
     513
     514Create a variable, in full generality. The keyword arguments have types below:
     515
     516 get_tostring : ()  -> string
     517 set_fromstring : string -> int
     518 -- optional --
     519 summary : string
     520 description : string
     521 validsettings : string
     522 takes_on_off : int
     523
     524The get/set functions are required. Note that the caller manages storage for the
     525variable. get_tostring/set_fromstring both convert AND store the value.
     526set_fromstring dies on failure.
     527
     528If the variable takes parameters 'on' and 'off' (i.e. is boolean-looking), set
     529takes_on_off to 1. This makes :set VAR and :unset VAR work. set_fromstring will
     530be called with those arguments.
     531
     532=cut
     533
     534sub new_variable_full {
    437535    my $name = shift;
    438536    my $args = shift || {};
    439537    my %args = (
    440         summary     => "",
     538        summary => "",
    441539        description => "",
    442         default     => $default_default,
     540        takes_on_off => 0,
     541        validsettings => "<string>",
    443542        %{$args});
    444     $func->($name, $args{default}, $args{summary}, $args{description});
     543
     544    die "get_tostring required" unless $args{get_tostring};
     545    die "set_fromstring required" unless $args{set_fromstring};
     546
     547    # Strip off the bogus dummy argument. Aargh perl-Glib.
     548    my $get_tostring_fn = sub { $args{get_tostring}->() };
     549    my $set_fromstring_fn = sub {
     550      my ($dummy, $val) = @_;
     551      # Translate from user-supplied die-on-failure callback to expected
     552      # non-zero on error. Less of a nuisance than interacting with ERRSV.
     553      eval { $args{set_fromstring}->($val) };
     554      # TODO: Consider changing B::I::new_variable to expect string|NULL with
     555      # string as the error message. That can then be translated to a GError in
     556      # owl_variable_set_fromstring. For now the string is ignored.
     557      return ($@ ? -1 : 0);
     558    };
     559
     560    BarnOwl::Internal::new_variable($name, $args{summary}, $args{description}, $args{validsettings},
     561                                    $args{takes_on_off}, $get_tostring_fn, $set_fromstring_fn, undef);
    445562}
    446563
     
    678795}
    679796
     797=head3 register_idle_watcher %ARGS
     798
     799Call a callback whenever the amount of time the user becomes idle or comes
     800back from being idle.
     801
     802You must include the following parameters:
     803
     804=over 4
     805
     806=item name
     807
     808The name given to the idle watcher
     809
     810=item after
     811
     812How long the user must be idle, in seconds, before the callback is called.
     813If the value is too small, you may have spurious or inaccurate calls.
     814(The current lower limit is about 1 second.)
     815
     816=item callback
     817
     818The Perl subroutine that gets called when the user has been idle for C<AFTER>
     819seconds, or comes back from being idle.  The subroutine is passed one parameter,
     820which is true if the user is currently idle, and false otherwise.
     821
     822=back
     823
     824This method returns a unique identifier which may be passed to
     825L<BarnOwl::unregister_idle_watcher>.
     826
     827=cut
     828
     829=head3 unregister_idle_watcher UNIQUE_ID [...]
     830
     831Removed and returns the idle watcher specified by C<UNIQUE_ID>.
     832You may specify multiple unique ids.
     833
     834=cut
     835
     836my %idle_watchers;
     837tie %idle_watchers, 'Tie::RefHash';
     838
     839$BarnOwl::Hooks::wakeup->add(sub {
     840        foreach my $idle_watcher (values %idle_watchers) {
     841            _wakeup_idle_watcher($idle_watcher);
     842        }
     843    });
     844
     845sub _wakeup_idle_watcher {
     846    my ($idle_watcher, $offset) = @_;
     847    $offset = 0 unless defined $offset;
     848    # go unidle
     849    $idle_watcher->{idle_timer}->stop if $idle_watcher->{idle_timer};
     850    undef $idle_watcher->{idle_timer};
     851    $idle_watcher->{callback}->(0) if $idle_watcher->{is_idle};
     852    $idle_watcher->{is_idle} = 0;
     853
     854    # queue going idle
     855    $idle_watcher->{idle_timer} = BarnOwl::Timer->new({
     856        name  => $idle_watcher->{name},
     857        after => $idle_watcher->{after} - $offset,
     858        cb    => sub {
     859            $idle_watcher->{is_idle} = 1;
     860            $idle_watcher->{callback}->(1);
     861        }
     862    });
     863}
     864
     865sub register_idle_watcher {
     866    my %args = (@_);
     867    $idle_watchers{\%args} = \%args;
     868    _wakeup_idle_watcher(\%args, BarnOwl::getidletime); # make sure to queue up the idle/unidle events from this idle watcher
     869    return \%args;
     870}
     871
     872sub unregister_idle_watcher {
     873    my ($id) = @_;
     874    $idle_watchers{$id}->{idle_timer}->stop if $idle_watchers{$id}->{idle_timer};
     875    return delete $idle_watchers{$id};
     876}
     877
    680878# Stub for owl::startup / BarnOwl::startup, so it isn't bound to the
    681879# startup command. This may be redefined in a user's configfile.
  • perl/lib/BarnOwl/Complete/Client.pm

    rd973a73 r4626016  
    2020
    2121my %show = (
    22     information => undef,
    2322    colors      => undef,
    2423    commands    => undef,
  • perl/lib/BarnOwl/Complete/Zephyr.pm

    r3e8625f re6e7842  
    6464BarnOwl::Completion::register_completer(viewuser  => \&complete_viewuser);
    6565BarnOwl::Completion::register_completer(vu        => \&complete_viewuser);
     66BarnOwl::Completion::register_completer(viewperson => \&complete_viewuser);
     67BarnOwl::Completion::register_completer(vp        => \&complete_viewuser);
    6668
    6769BarnOwl::Completion::register_completer(unsub     => \&complete_unsub);
  • perl/lib/BarnOwl/Hooks.pm

    rb8a3e00 r120dac7  
    3636Called before BarnOwl shutdown
    3737
     38=item $wakeup
     39
     40Called, at most once per second, on user input
     41
    3842=item $receiveMessage
    3943
     
    5761from every function registered with this hook will be appended and
    5862displayed in a popup window, with zephyr formatting parsed.
     63
     64=item $awayOn
     65
     66Called, for all protocol handlers, to go away, with the away message,
     67if any.
     68
     69=item $awayOff
     70
     71Called, for all protocol handlers, to come back from away.
     72
     73=item $getIsAway
     74
     75Called to check away status for all protocol handlers.  Protocol
     76handlers should return a true value if any account of the user is away
     77for the given protocol, and a false value otherwise.
    5978
    6079=item $getQuickstart
     
    7392
    7493our @EXPORT_OK = qw($startup $shutdown
     94                    $wakeup
    7595                    $receiveMessage $newMessage
    7696                    $mainLoop $getBuddyList
     97                    $awayOn $awayOff $getIsAway
    7798                    $getQuickstart);
    7899
     
    83104our $startup = BarnOwl::Hook->new;
    84105our $shutdown = BarnOwl::Hook->new;
     106our $wakeup = BarnOwl::Hook->new;
    85107our $receiveMessage = BarnOwl::Hook->new;
    86108our $newMessage = BarnOwl::Hook->new;
     
    88110our $getBuddyList = BarnOwl::Hook->new;
    89111our $getQuickstart = BarnOwl::Hook->new;
     112our $awayOn = BarnOwl::Hook->new;
     113our $awayOff = BarnOwl::Hook->new;
     114our $getIsAway = BarnOwl::Hook->new;
    90115
    91116# Internal startup/shutdown routines called by the C code
     
    175200}
    176201
     202sub _wakeup {
     203    $wakeup->run;
     204}
     205
    177206sub _receive_msg {
    178207    my $m = shift;
     
    199228sub _get_quickstart {
    200229    return join("\n", $getQuickstart->run);
     230}
     231
     232sub _away_on {
     233    $awayOn->run(@_);
     234}
     235
     236sub _away_off {
     237    $awayOff->run();
     238}
     239
     240sub _get_is_away {
     241    my @is_away = grep { $_ } $getIsAway->run();
     242    return scalar @is_away;
    201243}
    202244
  • perl/lib/BarnOwl/Message.pm

    ra130fc5 r0adbce1  
    5151sub is_ping     { return 0; }
    5252sub is_mail     { return 0; }
    53 sub is_personal { return shift->is_private; }
     53sub is_personal { return BarnOwl::message_matches_filter(shift, "personal"); }
    5454sub class       { return undef; }
    5555sub instance    { return undef; }
  • perl/lib/BarnOwl/Message/Zephyr.pm

    rbf70350 r0adbce1  
    5151    my ($m) = @_;
    5252    return undef if (!$m->is_loginout);
     53    return undef if (!defined($m->fields));
    5354    return $m->fields->[2];
    5455}
     
    5758    my ($m) = @_;
    5859    return undef if (!$m->is_loginout);
     60    return undef if (!defined($m->fields));
    5961    return $m->fields->[0];
    6062}
     
    6365
    6466sub is_ping     { return (lc(shift->opcode) eq "ping"); }
    65 
    66 sub is_personal {
    67     my ($m) = @_;
    68     return ((lc($m->class) eq "message")
    69             && $m->is_private);
    70 }
    7167
    7268sub is_mail {
  • perl/lib/BarnOwl/Zephyr.pm

    rdf569c5 r53151d4  
    1212use BarnOwl::Hook;
    1313
    14 my $zephyrStartup = BarnOwl::Hook->new;
     14our $zephyrStartup = BarnOwl::Hook->new;
    1515
    1616sub _zephyr_startup {
  • perl/lib/Module/Install/BarnOwl.pm

    rb8a3e00 re4b8f93  
    4141    my $class = ref $self;
    4242
     43    my $srcdir = $ENV{BARNOWL_SRCDIR} || '.';
     44
    4345    $self->name("BarnOwl-Module-$name");
    44     $self->all_from("lib/BarnOwl/Module/$name.pm");
     46    $self->all_from("$srcdir/lib/BarnOwl/Module/$name.pm");
     47    $self->makemaker_args(PMLIBDIRS => ["$srcdir/lib"],
     48                          PMLIBPARENTDIRS => ["$srcdir/lib"]);
    4549
    4650    $self->postamble(<<"END_MAKEFILE");
    4751
    4852# --- $class section:
     53
     54BARNOWL_SRCDIR = $srcdir
     55export BARNOWL_SRCDIR
    4956
    5057$name.par: pm_to_blib
  • perl/modules/IRC/lib/BarnOwl/Module/IRC.pm

    rb8a3e00 r4f7b1f4  
    2323use Getopt::Long;
    2424use Encode;
     25use Text::Wrap;
    2526
    2627our $VERSION = 0.02;
     
    6768       });
    6869
     70    BarnOwl::new_variable_int('irc:max-message-length', {
     71        default     => 450,
     72        summary     => 'Split messages to at most this many characters.' .
     73                       "If non-positive, don't split messages",
     74        description => 'If set to a positive number, any paragraph in an ' .
     75                       'IRC message will be split after this many characters.'
     76       });
     77
    6978    register_commands();
    7079    BarnOwl::filter(qw{irc type ^IRC$ or ( type ^admin$ and adminheader ^IRC$ )});
     
    129138argument listed above, and die if no channel argument can be found.
    130139
     140=item C<CHANNEL_OR_USER>
     141
     142Pass the channel argument, but accept it if it's a username (e.g.
     143has no hash).  Only relevant with C<CHANNEL_ARG>.
     144
    131145=item C<CHANNEL_OPTIONAL>
    132146
     
    145159use constant CHANNEL_ARG        => 1;
    146160use constant CHANNEL_OPTIONAL   => 2;
    147 
    148 use constant ALLOW_DISCONNECTED => 4;
     161use constant CHANNEL_OR_USER    => 4;
     162
     163use constant ALLOW_DISCONNECTED => 8;
    149164
    150165sub register_commands {
     
    188203
    189204    BarnOwl::new_command(
    190         'irc-msg' => mk_irc_command( \&cmd_msg ),
     205        'irc-msg' => mk_irc_command( \&cmd_msg, CHANNEL_OR_USER|CHANNEL_ARG|CHANNEL_OPTIONAL ),
    191206        {
    192207            summary => 'Send an IRC message',
     
    427442    @msgs = split "\n\n", $fullbody;
    428443    map { tr/\n/ / } @msgs;
     444    # split each body at irc:max-message-length characters, if that number
     445    # is positive.  Only split at space boundaries.  Start counting a-fresh
     446    # at the beginning of each paragraph
     447    my $max_len = BarnOwl::getvar('irc:max-message-length');
     448    if ($max_len > 0) {
     449        local($Text::Wrap::columns) = $max_len;
     450        @msgs = split "\n", wrap("", "", join "\n", @msgs);
     451    }
    429452    for my $body (@msgs) {
    430453        if ($body =~ /^\/me (.*)/) {
     
    591614                    $conn ||= $c;
    592615                }
     616            } elsif (defined($channel) && ($flags & CHANNEL_OR_USER)) {
     617                shift @ARGV;
    593618            } elsif ($m && $m->type eq 'IRC' && !$m->is_private) {
    594619                $channel = $m->channel;
     
    598623        }
    599624
    600         if(!$channel &&
     625        if(!defined($channel) &&
    601626           ($flags & CHANNEL_ARG) &&
    602627           !($flags & CHANNEL_OPTIONAL)) {
  • perl/modules/Jabber/lib/Net/Jabber/Component.pm

    rc2bed55 ra8c55b5  
    220220    $self->{STREAM}->SetCallBacks(node=>undef);
    221221
    222     $self->Send("<handshake>".Digest::SHA1::sha1_hex($self->{SESSION}->{id}.$args{secret})."</handshake>");
     222    $self->Send("<handshake>".Digest::SHA::sha1_hex($self->{SESSION}->{id}.$args{secret})."</handshake>");
    223223    my $handshake = $self->Process();
    224224
  • perl/modules/Jabber/lib/Net/Jabber/Key.pm

    rc2bed55 ra8c55b5  
    104104    $self->{CACHE} = {};
    105105
    106     if (eval "require Digest::SHA1")
     106    if (eval "require Digest::SHA")
    107107    {
    108108        $self->{DIGEST} = 1;
    109         Digest::SHA1->import(qw(sha1 sha1_hex sha1_base64));
     109        Digest::SHA->import(qw(sha1 sha1_hex sha1_base64));
    110110    }
    111111    else
    112112    {
    113         print "ERROR:  You cannot use Key.pm unless you have Digest::SHA1 installed.\n";
     113        print "ERROR:  You cannot use Key.pm unless you have Digest::SHA installed.\n";
    114114        exit(0);
    115115    }
     
    132132
    133133    my $string = $$.time.rand(1000000);
    134     $string = Digest::SHA1::sha1_hex($string);
     134    $string = Digest::SHA::sha1_hex($string);
    135135    $self->{DEBUG}->Log1("Generate: key($string)");
    136136    return $string;
  • perl/modules/Jabber/lib/Net/XMPP.pm

    rc2bed55 ra8c55b5  
    213213use Time::Local;
    214214use Carp;
    215 use Digest::SHA1;
     215use Digest::SHA;
    216216use Authen::SASL;
    217217use MIME::Base64;
  • perl/modules/Jabber/lib/Net/XMPP/Protocol.pm

    r7f33c18 ra8c55b5  
    18491849    if ($authType eq "zerok")
    18501850    {
    1851         my $hashA = Digest::SHA1::sha1_hex($password);
    1852         $args{hash} = Digest::SHA1::sha1_hex($hashA.$token);
     1851        my $hashA = Digest::SHA::sha1_hex($password);
     1852        $args{hash} = Digest::SHA::sha1_hex($hashA.$token);
    18531853
    18541854        for (1..$sequence)
    18551855        {
    1856             $args{hash} = Digest::SHA1::sha1_hex($args{hash});
     1856            $args{hash} = Digest::SHA::sha1_hex($args{hash});
    18571857        }
    18581858    }
     
    18681868    if ($authType eq "digest")
    18691869    {
    1870         $args{digest} = Digest::SHA1::sha1_hex($self->GetStreamID().$password);
     1870        $args{digest} = Digest::SHA::sha1_hex($self->GetStreamID().$password);
    18711871    }
    18721872
  • perl/modules/Makefile.am

    r35c5bd8 re4b8f93  
    11MODULES = Jabber IRC WordWrap Twitter Facebook
    22
    3 EXTRA_DIST = $(MODULES:=/Makefile.PL) $(MODULES:=/inc) $(MODULES:=/lib)
     3EXTRA_DIST = $(MODULES:=/Makefile.PL) $(MODULES:=/lib)
     4EXTRA_DIST += \
     5    Facebook/README \
     6    Twitter/README \
     7    Twitter/twitter.example
    48
    59all-local: $(MODULES)
     
    711        (cd $* && $(MAKE) $*.par)
    812
     13BARNOWL_PERL := $(shell which perl) -I$(abs_srcdir)/../lib
     14
    915MODULES_MAKEFILE = $(MODULES:=/Makefile)
    10 $(MODULES_MAKEFILE): %/Makefile: %/Makefile.PL
    11         $(AM_V_GEN)(cd $* && perl -I../../lib Makefile.PL)
     16$(MODULES_MAKEFILE): %/Makefile: %/Makefile.PL ../lib/Module/Install/BarnOwl.pm
     17        $(AM_V_GEN)test -d $* || mkdir $*
     18        $(AM_V_at)test $(srcdir) = . || $(LN_S) $(abs_srcdir)/$*/Makefile.PL $*/Makefile.PL
     19        $(AM_V_at)(cd $* && BARNOWL_SRCDIR='$(abs_srcdir)/$*' && export BARNOWL_SRCDIR && $(BARNOWL_PERL) Makefile.PL 'PERL=$(BARNOWL_PERL)')
    1220
    1321MODULES_CLEAN = $(MODULES:%=clean_%)
    1422clean-local: $(MODULES_CLEAN)
    1523$(MODULES_CLEAN): clean_%:
    16         (cd $* && (test ! -f Makefile || $(MAKE) clean))
     24        (cd $* && { test ! -f Makefile || $(MAKE) realclean; })
     25        rm -f $*/$*.par
     26        rm -rf $*/inc
     27        test $(srcdir) = . || rm -f $*/Makefile.PL
    1728
    1829MODULES_INSTALL = $(MODULES:%=module_install_%)
     
    2334        ${INSTALL_DATA} $*/$*.par ${DESTDIR}${pkgdatadir}/modules/$*.par
    2435
     36uninstall-local:
     37        rm -f $(MODULES:%=${DESTDIR}${pkgdatadir}/modules/%.par)
     38
    2539.PHONY: $(MODULES) $(MODULES_CLEAN) $(MODULES_INSTALL)
  • perlconfig.c

    rd199207 r96d80e9  
    9292                                      owl_new_sv(owl_message_get_##field(m)), 0)
    9393
    94   if (owl_message_get_notice(m)) {
     94  if (owl_message_is_type_zephyr(m) && owl_message_is_direction_in(m)) {
    9595    /* Handle zephyr-specific fields... */
    96     AV *av_zfields;
    97 
    98     av_zfields = newAV();
    99     for (f = owl_zephyr_first_raw_field(owl_message_get_notice(m)); f != NULL;
    100          f = owl_zephyr_next_raw_field(owl_message_get_notice(m), f)) {
    101       ptr=owl_zephyr_field_as_utf8(owl_message_get_notice(m), f);
    102       av_push(av_zfields, owl_new_sv(ptr));
    103       g_free(ptr);
     96    AV *av_zfields = newAV();
     97    if (owl_message_get_notice(m)) {
     98      for (f = owl_zephyr_first_raw_field(owl_message_get_notice(m)); f != NULL;
     99           f = owl_zephyr_next_raw_field(owl_message_get_notice(m), f)) {
     100        ptr = owl_zephyr_field_as_utf8(owl_message_get_notice(m), f);
     101        av_push(av_zfields, owl_new_sv(ptr));
     102        g_free(ptr);
     103      }
     104      (void)hv_store(h, "auth", strlen("auth"),
     105                     owl_new_sv(owl_zephyr_get_authstr(owl_message_get_notice(m))), 0);
     106    } else {
     107      /* Incoming zephyrs without a ZNotice_t are pseudo-logins. To appease
     108       * existing styles, put in bogus 'auth' and 'fields' keys. */
     109      (void)hv_store(h, "auth", strlen("auth"), owl_new_sv("NO"), 0);
    104110    }
    105111    (void)hv_store(h, "fields", strlen("fields"), newRV_noinc((SV*)av_zfields), 0);
    106 
    107     (void)hv_store(h, "auth", strlen("auth"),
    108                    owl_new_sv(owl_zephyr_get_authstr(owl_message_get_notice(m))),0);
    109112  }
    110113
     
    225228CALLER_OWN char *owl_perlconfig_call_with_message(const char *subname, const owl_message *m)
    226229{
    227   dSP ;
    228   int count;
    229   SV *msgref, *srv;
    230   char *out;
    231  
    232   ENTER ;
    233   SAVETMPS;
    234  
    235   PUSHMARK(SP) ;
     230  SV *msgref, *rv;
     231  char *out = NULL;
     232
    236233  msgref = owl_perlconfig_message2hashref(m);
    237   XPUSHs(sv_2mortal(msgref));
    238   PUTBACK ;
    239  
    240   count = call_pv(subname, G_SCALAR|G_EVAL);
    241  
    242   SPAGAIN ;
    243 
    244   if (SvTRUE(ERRSV)) {
    245     owl_function_error("Perl Error: '%s'", SvPV_nolen(ERRSV));
    246     /* and clear the error */
    247     sv_setsv (ERRSV, &PL_sv_undef);
    248   }
    249 
    250   if (count != 1) {
    251     fprintf(stderr, "bad perl!  no biscuit!  returned wrong count!\n");
    252     abort();
    253   }
    254 
    255   srv = POPs;
    256 
    257   if (srv) {
    258     out = g_strdup(SvPV_nolen(srv));
    259   } else {
    260     out = NULL;
    261   }
    262  
    263   PUTBACK ;
    264   FREETMPS ;
    265   LEAVE ;
    266 
     234
     235  OWL_PERL_CALL((call_pv(subname, G_SCALAR|G_EVAL))
     236                ,
     237                XPUSHs(sv_2mortal(msgref));
     238                ,
     239                "Perl Error: '%s'"
     240                ,
     241                false
     242                ,
     243                false
     244                ,
     245                rv = POPs;
     246                if (rv && SvPOK(rv))
     247                  out = g_strdup(SvPV_nolen(rv));
     248                );
    267249  return out;
    268250}
     
    274256CALLER_OWN char *owl_perlconfig_message_call_method(const owl_message *m, const char *method, int argc, const char **argv)
    275257{
    276   dSP;
    277   unsigned int count, i;
    278   SV *msgref, *srv;
    279   char *out;
     258  SV *msgref, *rv;
     259  char *out = NULL;
     260  int i;
    280261
    281262  msgref = owl_perlconfig_message2hashref(m);
    282263
    283   ENTER;
    284   SAVETMPS;
    285 
    286   PUSHMARK(SP);
    287   XPUSHs(sv_2mortal(msgref));
    288   for(i=0;i<argc;i++) {
    289     XPUSHs(sv_2mortal(owl_new_sv(argv[i])));
    290   }
    291   PUTBACK;
    292 
    293   count = call_method(method, G_SCALAR|G_EVAL);
    294 
    295   SPAGAIN;
    296 
    297   if(count != 1) {
    298     fprintf(stderr, "perl returned wrong count %u\n", count);
    299     abort();
    300   }
    301 
    302   if (SvTRUE(ERRSV)) {
    303     owl_function_error("Error: '%s'", SvPV_nolen(ERRSV));
    304     /* and clear the error */
    305     sv_setsv (ERRSV, &PL_sv_undef);
    306   }
    307 
    308   srv = POPs;
    309 
    310   if (srv) {
    311     out = g_strdup(SvPV_nolen(srv));
    312   } else {
    313     out = NULL;
    314   }
    315 
    316   PUTBACK;
    317   FREETMPS;
    318   LEAVE;
    319 
     264  OWL_PERL_CALL(call_method(method, G_SCALAR|G_EVAL)
     265                ,
     266                XPUSHs(sv_2mortal(msgref));
     267                OWL_PERL_PUSH_ARGS(i, argc, argv);
     268                ,
     269                "Perl Error: '%s'"
     270                ,
     271                false
     272                ,
     273                false
     274                ,
     275                rv = POPs;
     276                if (rv && SvPOK(rv))
     277                  out = g_strdup(SvPV_nolen(rv));
     278                );
    320279  return out;
    321280}
     
    328287  char *err;
    329288  const char *args[4] = {"", "-e", "0;", NULL};
     289  const char *dlerr;
    330290  AV *inc;
    331291  char *path;
     
    385345  g_free(path);
    386346
     347  /* Load up perl-Glib. */
     348  eval_pv("use Glib;", FALSE);
     349
     350  /* Now, before BarnOwl tries to use them, get the relevant function pointers out. */
     351  dlerr = owl_closure_init();
     352  if (dlerr) {
     353    return g_strdup(dlerr);
     354  }
     355
     356  /* And now it's safe to import BarnOwl. */
    387357  eval_pv("use BarnOwl;", FALSE);
    388358
     
    456426void owl_perlconfig_new_command(const char *name)
    457427{
    458   dSP;
    459 
    460   ENTER;
    461   SAVETMPS;
    462 
    463   PUSHMARK(SP);
    464   XPUSHs(sv_2mortal(owl_new_sv(name)));
    465   PUTBACK;
    466 
    467   call_pv("BarnOwl::Hooks::_new_command", G_VOID|G_EVAL);
    468 
    469   SPAGAIN;
    470 
    471   if(SvTRUE(ERRSV)) {
    472     owl_function_error("%s", SvPV_nolen(ERRSV));
    473   }
    474 
    475   FREETMPS;
    476   LEAVE;
     428  OWL_PERL_CALL(call_pv("BarnOwl::Hooks::_new_command", G_VOID|G_EVAL);
     429                ,
     430                XPUSHs(sv_2mortal(owl_new_sv(name)));
     431                ,
     432                "Perl Error: '%s'"
     433                ,
     434                false
     435                ,
     436                true
     437                ,
     438                );
     439}
     440
     441CALLER_OWN char *owl_perlconfig_perl_call(const char *method, int argc, const char *const *argv)
     442{
     443  SV *rv;
     444  char *out = NULL;
     445  int i;
     446  OWL_PERL_CALL(call_pv(method, G_SCALAR|G_EVAL)
     447                ,
     448                OWL_PERL_PUSH_ARGS(i, argc, argv);
     449                ,
     450                "Perl Error: '%s'"
     451                ,
     452                false
     453                ,
     454                false
     455                ,
     456                rv = POPs;
     457                if (rv && SvPOK(rv))
     458                  out = g_strdup(SvPV_nolen(rv));
     459                );
     460  return out;
     461}
     462
     463int owl_perlconfig_perl_call_int(const char *method, int argc, const char *const *argv)
     464{
     465  SV *rv;
     466  int ret = -1;
     467  int i;
     468  OWL_PERL_CALL(call_pv(method, G_SCALAR|G_EVAL)
     469                ,
     470                OWL_PERL_PUSH_ARGS(i, argc, argv);
     471                ,
     472                "Perl Error: '%s'"
     473                ,
     474                false
     475                ,
     476                false
     477                ,
     478                rv = POPs;
     479                if (rv && SvIOK(rv))
     480                  ret = SvIV(rv);
     481                );
     482  return ret;
     483}
     484
     485bool owl_perlconfig_perl_call_bool(const char *method, int argc, const char *const *argv)
     486{
     487  SV *rv;
     488  bool ret = false;
     489  int i;
     490  OWL_PERL_CALL(call_pv(method, G_SCALAR|G_EVAL)
     491                ,
     492                OWL_PERL_PUSH_ARGS(i, argc, argv);
     493                ,
     494                "Perl Error: '%s'"
     495                ,
     496                false
     497                ,
     498                false
     499                ,
     500                rv = POPs;
     501                if (rv)
     502                  ret = SvTRUE(rv);
     503                );
     504  return ret;
     505}
     506
     507void owl_perlconfig_perl_call_norv(const char *method, int argc, const char *const *argv)
     508{
     509  int i;
     510  OWL_PERL_CALL(call_pv(method, G_DISCARD|G_EVAL)
     511                ,
     512                OWL_PERL_PUSH_ARGS(i, argc, argv);
     513                ,
     514                "Perl Error: '%s'"
     515                ,
     516                false
     517                ,
     518                true
     519                ,
     520                );
    477521}
    478522
     
    480524CALLER_OWN char *owl_perlconfig_perlcmd(const owl_cmd *cmd, int argc, const char *const *argv)
    481525{
    482   int i, count;
    483   char * ret = NULL;
    484   SV *rv;
    485   dSP;
    486 
    487   ENTER;
    488   SAVETMPS;
    489 
    490   PUSHMARK(SP);
    491   for(i=0;i<argc;i++) {
    492     XPUSHs(sv_2mortal(owl_new_sv(argv[i])));
    493   }
    494   PUTBACK;
    495 
    496   count = call_sv(cmd->cmd_perl, G_SCALAR|G_EVAL);
    497 
    498   SPAGAIN;
    499 
    500   if(SvTRUE(ERRSV)) {
    501     owl_function_error("%s", SvPV_nolen(ERRSV));
    502     (void)POPs;
    503   } else {
    504     if(count != 1)
    505       croak("Perl command %s returned more than one value!", cmd->name);
    506     rv = POPs;
    507     if(SvTRUE(rv)) {
    508       ret = g_strdup(SvPV_nolen(rv));
    509     }
    510   }
    511 
    512   FREETMPS;
    513   LEAVE;
    514 
    515   return ret;
     526  int i;
     527  SV* rv;
     528  char *out = NULL;
     529
     530  OWL_PERL_CALL(call_sv(cmd->cmd_perl, G_SCALAR|G_EVAL)
     531                ,
     532                OWL_PERL_PUSH_ARGS(i, argc, argv);
     533                ,
     534                "Perl Error: '%s'"
     535                ,
     536                false
     537                ,
     538                false
     539                ,
     540                rv = POPs;
     541                if (rv && SvPOK(rv))
     542                  out = g_strdup(SvPV_nolen(rv));
     543                );
     544  return out;
    516545}
    517546
     
    524553{
    525554  SV *cb = owl_editwin_get_cbdata(e);
    526   SV *text;
    527   dSP;
    528 
    529   if(cb == NULL) {
     555  SV *text = owl_new_sv(owl_editwin_get_text(e));
     556
     557  if (cb == NULL) {
    530558    owl_function_error("Perl callback is NULL!");
    531559    return;
    532560  }
    533   text = owl_new_sv(owl_editwin_get_text(e));
    534 
    535   ENTER;
    536   SAVETMPS;
    537 
    538   PUSHMARK(SP);
    539   XPUSHs(sv_2mortal(text));
    540   XPUSHs(sv_2mortal(newSViv(success)));
    541   PUTBACK;
    542  
    543   call_sv(cb, G_DISCARD|G_EVAL);
    544 
    545   if(SvTRUE(ERRSV)) {
    546     owl_function_error("%s", SvPV_nolen(ERRSV));
    547   }
    548 
    549   FREETMPS;
    550   LEAVE;
     561
     562  OWL_PERL_CALL(call_sv(cb, G_DISCARD|G_EVAL)
     563                ,
     564                XPUSHs(sv_2mortal(text));
     565                XPUSHs(sv_2mortal(newSViv(success)));
     566                ,
     567                "Perl Error: '%s'"
     568                ,
     569                false
     570                ,
     571                true
     572                ,
     573                );
    551574}
    552575
  • perlglue.xs

    re89ec48 r1ced34f  
    6767        OUTPUT:
    6868                RETVAL
    69                
     69
     70int
     71getnumlines()
     72        CODE:
     73                RETVAL = owl_global_get_lines(&g);
     74        OUTPUT:
     75                RETVAL
     76
    7077time_t
    7178getidletime()
     
    8895        OUTPUT:
    8996                RETVAL
    90 
    91 void
    92 zephyr_zwrite(cmd,msg)
    93         const char *cmd
    94         const char *msg
    95         PREINIT:
    96                 int i;
    97         CODE:
    98                 i = owl_zwrite_create_and_send_from_line(cmd, msg);
    9997
    10098const utf8 *
     
    257255                }
    258256        }
     257
     258bool
     259message_matches_filter(message, filter_name, quiet = false)
     260        SV *message
     261        const char *filter_name
     262        bool quiet
     263        PREINIT:
     264                owl_message *m;
     265                const owl_filter *f;
     266        CODE:
     267        {
     268                if (!SvROK(message) || SvTYPE(SvRV(message)) != SVt_PVHV) {
     269                        croak("Usage: BarnOwl::message_matches_filter($message, $filter_name[, $quiet])");
     270                }
     271
     272                m = owl_perlconfig_hashref2message(message);
     273                f = owl_global_get_filter(&g, filter_name);
     274                if (!f && !quiet) {
     275                        owl_function_error("%s filter is not defined", filter_name);
     276                }
     277                RETVAL = f && owl_filter_message_match(f, m);
     278        }
     279        OUTPUT:
     280                RETVAL
     281        CLEANUP:
     282                owl_message_delete(m);
    259283
    260284const utf8 *
     
    404428           }
    405429
    406 void
    407 new_variable_string(name, ival, summ, desc)
    408         const char * name
    409         const char * ival
    410         const char * summ
    411         const char * desc
    412         CODE:
    413         owl_variable_dict_newvar_string(owl_global_get_vardict(&g),
    414                                         name,
    415                                         summ,
    416                                         desc,
    417                                         ival);
    418 
    419 void
    420 new_variable_int(name, ival, summ, desc)
    421         const char * name
    422         int ival
    423         const char * summ
    424         const char * desc
    425         CODE:
    426         owl_variable_dict_newvar_int(owl_global_get_vardict(&g),
    427                                      name,
    428                                      summ,
    429                                      desc,
    430                                      ival);
    431 
    432 void
    433 new_variable_bool(name, ival, summ, desc)
    434         const char * name
    435         int ival
    436         const char * summ
    437         const char * desc
    438         CODE:
    439         owl_variable_dict_newvar_bool(owl_global_get_vardict(&g),
    440                                       name,
    441                                       summ,
    442                                       desc,
    443                                       ival);
     430
     431MODULE = BarnOwl                PACKAGE = BarnOwl::Internal
     432
     433void
     434new_variable(name, summary, description, validsettings, takes_on_off, get_tostring_fn, set_fromstring_fn, data)
     435    const char *name
     436    const char *summary
     437    const char *description
     438    const char *validsettings
     439    int takes_on_off
     440    SV *get_tostring_fn
     441    SV *set_fromstring_fn
     442    SV *data
     443    CODE:
     444{
     445        /* data is somewhat redundant given we can create closures, but oh
     446         * well. Might be convenient sometimes. */
     447        if(!SV_IS_CODEREF(get_tostring_fn)) {
     448                croak("To-string function must be a coderef!");
     449        }
     450        if(!SV_IS_CODEREF(set_fromstring_fn)) {
     451                croak("From-string function must be a coderef!");
     452        }
     453
     454        owl_variable_dict_newvar_other(owl_global_get_vardict(&g),
     455                                       name, summary, description, validsettings, takes_on_off,
     456                                       perl_closure_new(get_tostring_fn, data, false),
     457                                       perl_closure_new(set_fromstring_fn, data, false));
     458}
    444459
    445460void
     
    468483        }
    469484
     485int
     486zephyr_zwrite(cmd,msg)
     487        const char *cmd
     488        const char *msg
     489        CODE:
     490                RETVAL = owl_zwrite_create_and_send_from_line(cmd, msg);
     491        OUTPUT:
     492                RETVAL
     493
    470494MODULE = BarnOwl                PACKAGE = BarnOwl::Editwin
    471495
  • runtests.sh

    rf6ab6ee r5db8835  
    11#!/bin/sh
    2 exec env HARNESS_PERL=./tester prove --failures t/
     2exec env HARNESS_PERL=./tester prove --failures "${srcdir:=$(dirname "$0")}/t/"
  • sepbar.c

    r6eb3ed9 ra38becd  
    6767  }
    6868
    69   if (owl_global_is_zaway(&g) || owl_global_is_aaway(&g)) {
     69  if (owl_function_is_away()) {
    7070    getyx(sepwin, y, x);
    7171    wmove(sepwin, y, x+2);
    7272    wattron(sepwin, A_BOLD);
    7373    wattroff(sepwin, A_REVERSE);
    74     if (owl_global_is_zaway(&g) && owl_global_is_aaway(&g)) {
    75       waddstr(sepwin, " AWAY ");
    76     } else if (owl_global_is_zaway(&g)) {
    77       waddstr(sepwin, " Z-AWAY ");
    78     } else if (owl_global_is_aaway(&g)) {
    79       waddstr(sepwin, " A-AWAY ");
    80     }
     74    waddstr(sepwin, " AWAY ");
    8175    wattron(sepwin, A_REVERSE);
    8276    wattroff(sepwin, A_BOLD);
  • style.c

    r14be3a5 r92ffd89  
    2323{
    2424  SV *sv = NULL;
    25   OWL_PERL_CALL_METHOD(s->perlobj,
    26                        "description",
    27                        ;,
    28                        "Error in style_get_description: %s",
    29                        0,
    30                        sv = SvREFCNT_inc(POPs);
    31                        );
    32   if(sv) {
     25  OWL_PERL_CALL(call_method("description", G_SCALAR|G_EVAL),
     26                XPUSHs(s->perlobj);,
     27                "Error in style_get_description: %s",
     28                0,
     29                false,
     30                sv = SvREFCNT_inc(POPs);
     31                );
     32  if (sv) {
    3333    return SvPV_nolen(sv_2mortal(sv));
    3434  } else {
     
    5050 
    5151  /* Call the perl object */
    52   OWL_PERL_CALL_METHOD(s->perlobj,
    53                        "format_message",
    54                        XPUSHs(sv_2mortal(owl_perlconfig_message2hashref(m)));,
    55                        "Error in format_message: %s",
    56                        0,
    57                        sv = SvREFCNT_inc(POPs);
    58                        );
     52  OWL_PERL_CALL(call_method("format_message", G_SCALAR|G_EVAL),
     53                XPUSHs(s->perlobj);
     54                XPUSHs(sv_2mortal(owl_perlconfig_message2hashref(m)));,
     55                "Error in format_message: %s",
     56                0,
     57                false,
     58                sv = SvREFCNT_inc(POPs);
     59                );
    5960
    60   if(sv) {
     61  if (sv) {
    6162    body = SvPV_nolen(sv);
    6263  } else {
  • t/00-core-tests.t

    r95414bf r5db8835  
    11#!/usr/bin/env perl
    2 use File::Basename;
    3 system(dirname($0) . "/../tester", "--builtin");
     2system("./tester", "--builtin");
  • tester.c

    r97cdbaf5 r6a8b519  
    133133{
    134134  int numfailed=0;
    135   char *s, *path, *home;
     135  char *path, *home;
    136136
    137137  printf("# BEGIN testing owl_util\n");
     
    229229
    230230
    231   s = owl_util_baseclass("barnowl");
    232   FAIL_UNLESS("baseclass barnowl", !strcmp("barnowl", s));
    233   g_free(s);
    234   s = owl_util_baseclass("unbarnowl");
    235   FAIL_UNLESS("baseclass unbarnowl", !strcmp("barnowl", s));
    236   g_free(s);
    237   s = owl_util_baseclass("unununbarnowl.d.d");
    238   FAIL_UNLESS("baseclass unununbarnowl.d.d", !strcmp("barnowl", s));
    239   g_free(s);
    240   s = owl_util_baseclass("ununun.d.d");
    241   FAIL_UNLESS("baseclass ununun.d.d", !strcmp("", s));
    242   g_free(s);
    243   s = owl_util_baseclass("d.d.d.d");
    244   FAIL_UNLESS("baseclass d.d.d.d", !strcmp("d", s));
    245   g_free(s);
    246   s = owl_util_baseclass("n.d.d.d");
    247   FAIL_UNLESS("baseclass n.d.d.d", !strcmp("n", s));
    248   g_free(s);
    249   s = owl_util_baseclass("ununun.");
    250   FAIL_UNLESS("baseclass ununun.", !strcmp(".", s));
    251   g_free(s);
    252   s = owl_util_baseclass("unununu");
    253   FAIL_UNLESS("baseclass unununu", !strcmp("u", s));
    254   g_free(s);
    255 
    256 
    257   s = owl_util_makepath("foo/bar");
    258   FAIL_UNLESS("makepath foo/bar", !strcmp("foo/bar", s));
    259   g_free(s);
    260   s = owl_util_makepath("//foo///bar");
    261   FAIL_UNLESS("makepath //foo///bar", !strcmp("/foo/bar", s));
    262   g_free(s);
    263   s = owl_util_makepath("foo/~//bar/");
    264   FAIL_UNLESS("makepath foo/~//bar/", !strcmp("foo/~/bar/", s));
    265   g_free(s);
    266   s = owl_util_makepath("~thisuserhadreallybetternotexist/foobar/");
    267   FAIL_UNLESS("makepath ~thisuserhadreallybetternotexist/foobar/",
    268               !strcmp("~thisuserhadreallybetternotexist/foobar/", s));
    269   g_free(s);
     231  CHECK_STR_AND_FREE("baseclass barnowl",
     232                     "barnowl", owl_util_baseclass("barnowl"));
     233  CHECK_STR_AND_FREE("baseclass unbarnowl",
     234                     "barnowl", owl_util_baseclass("unbarnowl"));
     235  CHECK_STR_AND_FREE("baseclass unununbarnowl.d.d",
     236                     "barnowl", owl_util_baseclass("unununbarnowl.d.d"));
     237  CHECK_STR_AND_FREE("baseclass ununun.d.d",
     238                     "", owl_util_baseclass("ununun.d.d"));
     239  CHECK_STR_AND_FREE("baseclass d.d.d.d",
     240                     "d", owl_util_baseclass("d.d.d.d"));
     241  CHECK_STR_AND_FREE("baseclass n.d.d.d",
     242                     "n", owl_util_baseclass("n.d.d.d"));
     243  CHECK_STR_AND_FREE("baseclass ununun.",
     244                     ".", owl_util_baseclass("ununun."));
     245  CHECK_STR_AND_FREE("baseclass unununu",
     246                     "u", owl_util_baseclass("unununu"));
     247
     248
     249  CHECK_STR_AND_FREE("makepath foo/bar",
     250                     "foo/bar", owl_util_makepath("foo/bar"));
     251  CHECK_STR_AND_FREE("makepath //foo///bar",
     252                     "/foo/bar", owl_util_makepath("//foo///bar"));
     253  CHECK_STR_AND_FREE("makepath foo/~//bar/",
     254                     "foo/~/bar/", owl_util_makepath("foo/~//bar/"));
     255  CHECK_STR_AND_FREE("makepath ~thisuserhadreallybetternotexist/foobar/",
     256                     "~thisuserhadreallybetternotexist/foobar/",
     257                     owl_util_makepath("~thisuserhadreallybetternotexist/foobar/"));
    270258
    271259  home = g_strdup(owl_global_get_homedir(&g));
    272   s = owl_util_makepath("~");
    273   FAIL_UNLESS("makepath ~", !strcmp(home, s));
    274   g_free(s);
     260  CHECK_STR_AND_FREE("makepath ~",
     261                     home, owl_util_makepath("~"));
    275262
    276263  path = g_build_filename(home, "foo/bar/baz", NULL);
    277   s = owl_util_makepath("~///foo/bar//baz");
    278   FAIL_UNLESS("makepath ~///foo/bar//baz", !strcmp(path, s));
    279   g_free(s);
     264  CHECK_STR_AND_FREE("makepath ~///foo/bar//baz",
     265                     path, owl_util_makepath("~///foo/bar//baz"));
    280266  g_free(path);
    281267  g_free(home);
     
    288274  }
    289275
    290   s = owl_util_makepath("~root");
    291   FAIL_UNLESS("makepath ~root", !strcmp(home, s));
    292   g_free(s);
     276  CHECK_STR_AND_FREE("makepath ~root",
     277                     home, owl_util_makepath("~root"));
    293278
    294279  path = g_build_filename(home, "foo/bar/baz", NULL);
    295   s = owl_util_makepath("~root///foo/bar//baz");
    296   FAIL_UNLESS("makepath ~root///foo/bar//baz", !strcmp(path, s));
    297   g_free(s);
     280  CHECK_STR_AND_FREE("makepath ~root///foo/bar//baz",
     281                     path, owl_util_makepath("~root///foo/bar//baz"));
    298282  g_free(path);
    299283  g_free(home);
     
    353337  int numfailed=0;
    354338  char *value;
    355   const void *v;
    356339
    357340  printf("# BEGIN testing owl_variable\n");
    358   FAIL_UNLESS("setup", 0==owl_variable_dict_setup(&vd));
     341  owl_variable_dict_setup(&vd);
    359342
    360343  FAIL_UNLESS("get bool var", NULL != (var = owl_variable_get_var(&vd, "rxping")));
     
    393376  FAIL_UNLESS("get int 7", 9 == owl_variable_get_int(var));
    394377
    395   owl_variable_dict_newvar_string(&vd, "stringvar", "", "", "testval");
     378  FAIL_UNLESS("get enum var", NULL != (var = owl_variable_get_var(&vd, "scrollmode")));
     379  FAIL_UNLESS("get enum", OWL_SCROLLMODE_NORMAL == owl_variable_get_int(var));
     380  FAIL_UNLESS("get enum as string",
     381              !strcmp((value = owl_variable_get_tostring(var)), "normal"));
     382  g_free(value);
     383  FAIL_UNLESS("set enum 1", 0 == owl_variable_set_int(var, OWL_SCROLLMODE_TOP));
     384  FAIL_UNLESS("get enum 1", OWL_SCROLLMODE_TOP == owl_variable_get_int(var));
     385  FAIL_UNLESS("set enum 2a", -1 == owl_variable_set_int(var, -1));
     386  FAIL_UNLESS("set enum 2b", -1 == owl_variable_set_int(var, OWL_SCROLLMODE_PAGEDCENTER + 1));
     387  FAIL_UNLESS("get enum 2", OWL_SCROLLMODE_TOP == owl_variable_get_int(var));
     388  FAIL_UNLESS("set enum 3", 0 == owl_variable_set_fromstring(var, "center", 0));
     389  FAIL_UNLESS("get enum 4", OWL_SCROLLMODE_CENTER == owl_variable_get_int(var));
     390  FAIL_UNLESS("set enum 5", -1 == owl_variable_set_fromstring(var, "bogus", 0));
     391  FAIL_UNLESS("set enum 6", -1 == owl_variable_set_fromstring(var, "", 0));
     392  FAIL_UNLESS("get enum 7", OWL_SCROLLMODE_CENTER == owl_variable_get_int(var));
     393
     394  owl_variable_dict_newvar_string(&vd, "stringvar", "testval", "", "");
    396395  FAIL_UNLESS("get new string var", NULL != (var = owl_variable_get_var(&vd, "stringvar")));
    397   FAIL_UNLESS("get new string var", NULL != (v = owl_variable_get(var)));
    398396  FAIL_UNLESS("get new string val", !strcmp("testval", owl_variable_get_string(var)));
    399397  owl_variable_set_string(var, "new val");
    400398  FAIL_UNLESS("update string val", !strcmp("new val", owl_variable_get_string(var)));
    401399
    402   owl_variable_dict_newvar_int(&vd, "intvar", "", "", 47);
     400  owl_variable_dict_newvar_int(&vd, "intvar", 47, "", "");
    403401  FAIL_UNLESS("get new int var", NULL != (var = owl_variable_get_var(&vd, "intvar")));
    404   FAIL_UNLESS("get new int var", NULL != (v = owl_variable_get(var)));
    405402  FAIL_UNLESS("get new int val", 47 == owl_variable_get_int(var));
    406403  owl_variable_set_int(var, 17);
    407404  FAIL_UNLESS("update int val", 17 == owl_variable_get_int(var));
    408405
    409   owl_variable_dict_newvar_bool(&vd, "boolvar", "", "", 1);
     406  owl_variable_dict_newvar_bool(&vd, "boolvar", true, "", "");
    410407  FAIL_UNLESS("get new bool var", NULL != (var = owl_variable_get_var(&vd, "boolvar")));
    411   FAIL_UNLESS("get new bool var", NULL != (v = owl_variable_get(var)));
    412408  FAIL_UNLESS("get new bool val", owl_variable_get_bool(var));
    413409  owl_variable_set_bool_off(var);
    414410  FAIL_UNLESS("update bool val", !owl_variable_get_bool(var));
    415411
    416   owl_variable_dict_newvar_string(&vd, "nullstringvar", "", "", NULL);
     412  owl_variable_dict_newvar_string(&vd, "nullstringvar", NULL, "", "");
    417413  FAIL_UNLESS("get new string (NULL) var", NULL != (var = owl_variable_get_var(&vd, "nullstringvar")));
    418414  FAIL_UNLESS("get string (NULL)", NULL == (value = owl_variable_get_tostring(var)));
     
    421417  FAIL_UNLESS("get string (NULL) 2", NULL == (value = owl_variable_get_tostring(var)));
    422418  g_free(value);
     419
     420  owl_variable_dict_newvar_enum(&vd, "enumvar", 0, "", "", "a,b,c,d");
     421  FAIL_UNLESS("get new enum var", NULL != (var = owl_variable_get_var(&vd, "enumvar")));
     422  FAIL_UNLESS("get new enum val", 0 == owl_variable_get_int(var));
     423  owl_variable_set_fromstring(var, "c", 0);
     424  FAIL_UNLESS("update enum val", 2 == owl_variable_get_int(var));
    423425
    424426  owl_variable_dict_cleanup(&vd);
  • variable.c

    rd126a19 r9d4dfdc  
    11#include "owl.h"
    22#include <stdio.h>
    3 
    4 #define OWLVAR_BOOL(name,default,summary,description) \
    5         { g_strdup(name), OWL_VARIABLE_BOOL, NULL, default, "on,off", g_strdup(summary), g_strdup(description), NULL, \
    6         NULL, NULL, NULL, NULL, NULL, NULL }
    7 
    8 #define OWLVAR_BOOL_FULL(name,default,summary,description,validate,set,get) \
    9         { g_strdup(name), OWL_VARIABLE_BOOL, NULL, default, "on,off", g_strdup(summary), g_strdup(description), NULL, \
    10         validate, set, NULL, get, NULL, NULL }
    11 
    12 #define OWLVAR_INT(name,default,summary,description) \
    13         { g_strdup(name), OWL_VARIABLE_INT, NULL, default, "<int>", g_strdup(summary), g_strdup(description), NULL, \
    14         NULL, NULL, NULL, NULL, NULL, NULL }
     3#include "gmarshal_funcs.h"
     4
     5/* TODO(davidben): When we can require 2.30 and up, remove this. */
     6#ifndef G_VALUE_INIT
     7#define G_VALUE_INIT { 0, { { 0 } } }
     8#endif
     9
     10typedef const char *(*get_string_t)(const owl_variable *);
     11typedef int (*get_int_t)(const owl_variable *);
     12typedef bool (*get_bool_t)(const owl_variable *);
     13
     14typedef int (*set_string_t)(owl_variable *, const char *);
     15typedef int (*set_int_t)(owl_variable *, int);
     16typedef int (*set_bool_t)(owl_variable *, bool);
     17
     18typedef int (*validate_string_t)(const owl_variable *, const char *);
     19typedef int (*validate_int_t)(const owl_variable *, int);
     20typedef int (*validate_bool_t)(const owl_variable *, bool);
     21
     22static void owl_variable_dict_newvar_bool_full(owl_vardict *vd,
     23                                               const char *name,
     24                                               bool default_val,
     25                                               const char *summary,
     26                                               const char *description,
     27                                               validate_bool_t validate_fn,
     28                                               set_bool_t set_fn,
     29                                               get_bool_t get_fn);
     30
     31static void owl_variable_dict_newvar_string_full(owl_vardict *vd,
     32                                                 const char *name,
     33                                                 const char *default_val,
     34                                                 const char *summary,
     35                                                 const char *description,
     36                                                 const char *validsettings,
     37                                                 validate_string_t validate_fn,
     38                                                 set_string_t set_fn,
     39                                                 get_string_t get_fn);
     40
     41static void owl_variable_dict_newvar_int_full(owl_vardict *vd,
     42                                              const char *name,
     43                                              int default_val,
     44                                              const char *summary,
     45                                              const char *description,
     46                                              const char *validsettings,
     47                                              validate_int_t validate_fn,
     48                                              set_int_t set_fn,
     49                                              get_int_t get_fn);
     50
     51static void owl_variable_dict_newvar_enum_full(owl_vardict *vd,
     52                                               const char *name,
     53                                               int default_val,
     54                                               const char *summary,
     55                                               const char *description,
     56                                               const char *validsettings,
     57                                               validate_int_t validate_fn,
     58                                               set_int_t set_fn,
     59                                               get_int_t get_fn);
     60
     61#define OWLVAR_BOOL(name, default, summary, description) \
     62        owl_variable_dict_newvar_bool(vd, name, default, summary, description)
     63
     64#define OWLVAR_BOOL_FULL(name, default, summary, description, validate, set, get) \
     65        owl_variable_dict_newvar_bool_full(vd, name, default, summary, description, \
     66                                           validate, set, get)
     67
     68#define OWLVAR_INT(name, default, summary, description) \
     69        owl_variable_dict_newvar_int(vd, name, default, summary, description)
    1570
    1671#define OWLVAR_INT_FULL(name,default,summary,description,validset,validate,set,get) \
    17         { g_strdup(name), OWL_VARIABLE_INT, NULL, default, validset, g_strdup(summary), g_strdup(description), NULL, \
    18         validate, set, NULL, get, NULL, NULL }
    19 
    20 #define OWLVAR_PATH(name,default,summary,description) \
    21         { g_strdup(name), OWL_VARIABLE_STRING, g_strdup(default), 0, "<path>", g_strdup(summary), g_strdup(description),  NULL, \
    22         NULL, NULL, NULL, NULL, NULL, NULL }
    23 
    24 #define OWLVAR_STRING(name,default,summary,description) \
    25         { g_strdup(name), OWL_VARIABLE_STRING, g_strdup(default), 0, "<string>", g_strdup(summary), g_strdup(description), NULL, \
    26         NULL, NULL, NULL, NULL, NULL, NULL }
    27 
    28 #define OWLVAR_STRING_FULL(name,default,validset,summary,description,validate,set,get) \
    29         { g_strdup(name), OWL_VARIABLE_STRING, g_strdup(default), 0, validset, g_strdup(summary), g_strdup(description), NULL, \
    30         validate, set, NULL, get, NULL, NULL }
     72        owl_variable_dict_newvar_int_full(vd, name, default, summary, description, \
     73                                          validset, validate, set, get)
     74
     75#define OWLVAR_PATH(name, default, summary, description) \
     76        owl_variable_dict_newvar_path(vd, name, default, summary, description)
     77
     78#define OWLVAR_STRING(name, default, summary, description) \
     79        owl_variable_dict_newvar_string(vd, name, default, summary, description)
     80
     81#define OWLVAR_STRING_FULL(name, default, validset, summary, description, validate, set, get) \
     82        owl_variable_dict_newvar_string_full(vd, name, default, summary, description, \
     83                                             validset, validate, set, get)
    3184
    3285/* enums are really integers, but where validset is a comma-separated
    3386 * list of strings which can be specified.  The tokens, starting at 0,
    3487 * correspond to the values that may be specified. */
    35 #define OWLVAR_ENUM(name,default,summary,description,validset) \
    36         { g_strdup(name), OWL_VARIABLE_INT, NULL, default, validset, g_strdup(summary), g_strdup(description), NULL, \
    37         owl_variable_enum_validate, \
    38         NULL, owl_variable_enum_set_fromstring, \
    39         NULL, owl_variable_enum_get_tostring, \
    40         NULL }
     88#define OWLVAR_ENUM(name, default, summary, description, validset) \
     89        owl_variable_dict_newvar_enum(vd, name, default, summary, description, validset)
    4190
    4291#define OWLVAR_ENUM_FULL(name,default,summary,description,validset,validate, set, get) \
    43         { g_strdup(name), OWL_VARIABLE_INT, NULL, default, validset, g_strdup(summary), g_strdup(description), NULL, \
    44         validate, \
    45         set, owl_variable_enum_set_fromstring, \
    46         get, owl_variable_enum_get_tostring, \
    47         NULL }
    48 
    49 int owl_variable_add_defaults(owl_vardict *vd)
    50 {
    51   owl_variable variables_to_init[] = {
    52 
     92        owl_variable_dict_newvar_enum_full(vd, name, default, summary, description, \
     93                                           validset, validate, set, get)
     94
     95void owl_variable_add_defaults(owl_vardict *vd)
     96{
    5397  OWLVAR_STRING( "personalbell" /* %OwlVarStub */, "off",
    5498                 "ring the terminal bell when personal messages are received",
    5599                 "Can be set to 'on', 'off', or the name of a filter which\n"
    56                  "messages need to match in order to ring the bell"),
     100                 "messages need to match in order to ring the bell");
    57101
    58102  OWLVAR_BOOL( "bell" /* %OwlVarStub */, 1,
    59                "enable / disable the terminal bell", "" ),
     103               "enable / disable the terminal bell", "" );
    60104
    61105  OWLVAR_BOOL_FULL( "debug" /* %OwlVarStub */, OWL_DEBUG,
     
    63107                    "If set to 'on', debugging messages are logged to the\n"
    64108                    "file specified by the debugfile variable.\n",
    65                     NULL, owl_variable_debug_set, NULL),
     109                    NULL, owl_variable_debug_set, NULL);
    66110
    67111  OWLVAR_BOOL( "startuplogin" /* %OwlVarStub */, 1,
    68                "send a login message when BarnOwl starts", "" ),
     112               "send a login message when BarnOwl starts", "" );
    69113
    70114  OWLVAR_BOOL( "shutdownlogout" /* %OwlVarStub */, 1,
    71                "send a logout message when BarnOwl exits", "" ),
     115               "send a logout message when BarnOwl exits", "" );
    72116
    73117  OWLVAR_BOOL( "rxping" /* %OwlVarStub */, 0,
    74                "display received pings", "" ),
     118               "display received pings", "" );
    75119
    76120  OWLVAR_BOOL( "txping" /* %OwlVarStub */, 1,
    77                "send pings", "" ),
     121               "send pings", "" );
    78122
    79123  OWLVAR_BOOL( "sepbar_disable" /* %OwlVarStub */, 0,
    80                "disable printing information in the separator bar", "" ),
     124               "disable printing information in the separator bar", "" );
    81125
    82126  OWLVAR_BOOL( "smartstrip" /* %OwlVarStub */, 1,
    83                "strip kerberos instance for reply", ""),
     127               "strip kerberos instance for reply", "");
    84128
    85129  OWLVAR_BOOL( "newlinestrip" /* %OwlVarStub */, 1,
    86                "strip leading and trailing newlines", ""),
     130               "strip leading and trailing newlines", "");
    87131
    88132  OWLVAR_BOOL( "displayoutgoing" /* %OwlVarStub */, 1,
    89                "display outgoing messages", "" ),
     133               "display outgoing messages", "" );
    90134
    91135  OWLVAR_BOOL( "loginsubs" /* %OwlVarStub */, 1,
    92                "load logins from .anyone on startup", "" ),
     136               "load logins from .anyone on startup", "" );
    93137
    94138  OWLVAR_BOOL( "logging" /* %OwlVarStub */, 0,
     
    97141               "logged in the directory specified\n"
    98142               "by the 'logpath' variable.  The filename in that\n"
    99                "directory is derived from the sender of the message.\n" ),
     143               "directory is derived from the sender of the message.\n" );
    100144
    101145  OWLVAR_BOOL( "classlogging" /* %OwlVarStub */, 0,
     
    105149               "by the 'classlogpath' variable.\n"
    106150               "The filename in that directory is derived from\n"
    107                "the name of the class to which the message was sent.\n" ),
     151               "the name of the class to which the message was sent.\n" );
    108152
    109153  OWLVAR_ENUM( "loggingdirection" /* %OwlVarStub */, OWL_LOGGING_DIRECTION_BOTH,
     
    114158               "is selected both incoming and outgoing messages are\n"
    115159               "logged.",
    116                "both,in,out"),
     160               "both,in,out");
    117161
    118162  OWLVAR_BOOL_FULL( "colorztext" /* %OwlVarStub */, 1,
    119163                    "allow @color() in zephyrs to change color",
    120                     NULL, NULL, owl_variable_colorztext_set, NULL),
     164                    NULL, NULL, owl_variable_colorztext_set, NULL);
    121165
    122166  OWLVAR_BOOL( "fancylines" /* %OwlVarStub */, 1,
     
    124168               "If turned off, dashes, pipes and pluses will be used\n"
    125169               "to draw lines on the screen.  Useful when the terminal\n"
    126                "is causing problems" ),
     170               "is causing problems" );
    127171
    128172  OWLVAR_BOOL( "zcrypt" /* %OwlVarStub */, 1,
    129173               "Do automatic zcrypt processing",
    130                "" ),
     174               "" );
    131175
    132176  OWLVAR_BOOL_FULL( "pseudologins" /* %OwlVarStub */, 0,
     
    136180                    "but sent no login message, or a user is not present that sent no\n"
    137181                    "logout message, a pseudo login or logout message will be created\n",
    138                     NULL, owl_variable_pseudologins_set, NULL),
     182                    NULL, owl_variable_pseudologins_set, NULL);
    139183
    140184  OWLVAR_BOOL( "ignorelogins" /* %OwlVarStub */, 0,
     
    142186               "When this is enabled, BarnOwl will print login and logout notifications\n"
    143187               "for AIM, zephyr, or other protocols.  If disabled BarnOwl will not print\n"
    144                "login or logout notifications.\n"),
     188               "login or logout notifications.\n");
    145189
    146190  OWLVAR_STRING( "logfilter" /* %OwlVarStub */, "",
     
    151195                 "variables like logging, classlogging, loglogins, loggingdirection,\n"
    152196                 "etc.  If you want this variable to control all logging, make sure\n"
    153                  "all other logging variables are in their default state.\n"),
     197                 "all other logging variables are in their default state.\n");
    154198
    155199  OWLVAR_BOOL( "loglogins" /* %OwlVarStub */, 0,
     
    157201               "When this is enabled, BarnOwl will log login and logout notifications\n"
    158202               "for AIM, zephyr, or other protocols.  If disabled BarnOwl will not print\n"
    159                "login or logout notifications.\n"),
     203               "login or logout notifications.\n");
    160204
    161205  OWLVAR_ENUM_FULL( "disable-ctrl-d" /* %OwlVarStub:lockout_ctrld */, 1,
     
    169213                    "in the editmulti keymap.\n",
    170214                    "off,middle,on",
    171                     NULL, owl_variable_disable_ctrl_d_set, NULL),
     215                    NULL, owl_variable_disable_ctrl_d_set, NULL);
    172216
    173217  OWLVAR_PATH( "logpath" /* %OwlVarStub */, "~/zlog/people",
    174218               "path for logging personal zephyrs",
    175219               "Specifies a directory which must exist.\n"
    176                "Files will be created in the directory for each sender.\n"),
     220               "Files will be created in the directory for each sender.\n");
    177221
    178222  OWLVAR_PATH( "classlogpath" /* %OwlVarStub:classlogpath */, "~/zlog/class",
    179223               "path for logging class zephyrs",
    180224               "Specifies a directory which must exist.\n"
    181                "Files will be created in the directory for each class.\n"),
     225               "Files will be created in the directory for each class.\n");
    182226
    183227  OWLVAR_PATH( "debug_file" /* %OwlVarStub */, OWL_DEBUG_FILE,
    184228               "path for logging debug messages when debugging is enabled",
    185229               "This file will be logged to if 'debug' is set to 'on'.\n"
    186                "BarnOwl will append a dot and the current process's pid to the filename."),
     230               "BarnOwl will append a dot and the current process's pid to the filename.");
    187231 
    188232  OWLVAR_PATH( "zsigproc" /* %OwlVarStub:zsigproc */, NULL,
     
    192236               "See the documentation for 'zsig' for more information about\n"
    193237               "how the outgoing zsig is chosen."
    194                ),
     238               );
    195239
    196240  OWLVAR_PATH( "newmsgproc" /* %OwlVarStub:newmsgproc */, NULL,
     
    198242               "The named program will be run when BarnOwl receives new\n"
    199243               "messages.  It will not be run again until the first\n"
    200                "instance exits"),
     244               "instance exits");
    201245
    202246  OWLVAR_STRING( "zsender" /* %OwlVarStub */, "",
     
    205249         "zephyrs.  If this is unset, it will use your Kerberos\n"
    206250         "principal. Note that customizing the sender name will\n"
    207          "cause your zephyrs to be sent unauthenticated."),
     251         "cause your zephyrs to be sent unauthenticated.");
    208252
    209253  OWLVAR_STRING( "zsigfunc" /* %OwlVarStub */, "BarnOwl::default_zephyr_signature()",
     
    212256                 "explicit zsig.  The default setting implements the policy\n"
    213257                 "described in the documentation for the 'zsig' variable.\n"
    214                  "See also BarnOwl::random_zephyr_signature().\n"),
     258                 "See also BarnOwl::random_zephyr_signature().\n");
    215259
    216260  OWLVAR_STRING( "zsig" /* %OwlVarStub */, "",
     
    219263                 "unset, 'zsigproc' will be run to generate a zsig. If that is\n"
    220264                 "also unset, the 'zwrite-signature' zephyr variable will be\n"
    221                  "used instead.\n"),
     265                 "used instead.\n");
    222266
    223267  OWLVAR_STRING( "appendtosepbar" /* %OwlVarStub */, "",
     
    225269                 "The sepbar is the bar separating the top and bottom\n"
    226270                 "of the BarnOwl screen.  Any string specified here will\n"
    227                  "be displayed on the right of the sepbar\n"),
     271                 "be displayed on the right of the sepbar\n");
    228272
    229273  OWLVAR_BOOL( "zaway" /* %OwlVarStub */, 0,
    230                "turn zaway on or off", "" ),
     274               "turn zaway on or off", "" );
    231275
    232276  OWLVAR_STRING( "zaway_msg" /* %OwlVarStub */,
    233277                 OWL_DEFAULT_ZAWAYMSG,
    234                  "zaway msg for responding to zephyrs when away", "" ),
     278                 "zaway msg for responding to zephyrs when away", "" );
    235279
    236280  OWLVAR_STRING( "zaway_msg_default" /* %OwlVarStub */,
    237281                 OWL_DEFAULT_ZAWAYMSG,
    238                  "default zaway message", "" ),
     282                 "default zaway message", "" );
    239283
    240284  OWLVAR_BOOL_FULL( "aaway" /* %OwlVarStub */, 0,
    241285                    "Set AIM away status",
    242286                    "",
    243                     NULL, owl_variable_aaway_set, NULL),
     287                    NULL, owl_variable_aaway_set, NULL);
    244288
    245289  OWLVAR_STRING( "aaway_msg" /* %OwlVarStub */,
    246290                 OWL_DEFAULT_AAWAYMSG,
    247                  "AIM away msg for responding when away", "" ),
     291                 "AIM away msg for responding when away", "" );
    248292
    249293  OWLVAR_STRING( "aaway_msg_default" /* %OwlVarStub */,
    250294                 OWL_DEFAULT_AAWAYMSG,
    251                  "default AIM away message", "" ),
     295                 "default AIM away message", "" );
    252296
    253297  OWLVAR_STRING( "view_home" /* %OwlVarStub */, "all",
    254298                 "home view to switch to after 'X' and 'V'",
    255                  "SEE ALSO: view, filter\n" ),
     299                 "SEE ALSO: view, filter\n" );
    256300
    257301  OWLVAR_STRING( "alert_filter" /* %OwlVarStub */, "none",
    258302                 "filter on which to trigger alert actions",
    259                  "" ),
     303                 "" );
    260304
    261305  OWLVAR_STRING( "alert_action" /* %OwlVarStub */, "nop",
    262306                 "BarnOwl command to execute for alert actions",
    263                  "" ),
     307                 "" );
    264308
    265309  OWLVAR_STRING_FULL( "tty" /* %OwlVarStub */, "", "<string>", "tty name for zephyr location", "",
    266                       NULL, owl_variable_tty_set, NULL),
     310                      NULL, owl_variable_tty_set, NULL);
    267311
    268312  OWLVAR_STRING( "default_style" /* %OwlVarStub */, "default",
     
    275319                 "   perl     - legacy perl interface\n"
    276320                 "\nSEE ALSO: style, show styles, view -s <style>\n"
    277                  ),
     321                 );
    278322
    279323
     
    282326                 "This specifies the maximum number of columns for M-q to fill text\n"
    283327                 "to.  If set to 0, M-q will wrap to the width of the window, and\n"
    284                  "values less than 0 disable M-q entirely.\n"),
     328                 "values less than 0 disable M-q entirely.\n");
    285329
    286330  OWLVAR_INT(    "edit:maxwrapcols" /* %OwlVarStub:edit_maxwrapcols */, 70,
     
    291335                 "\n"
    292336                 "As a courtesy to recipients, it is recommended that outgoing\n"
    293                  "Zephyr messages be no wider than 70 columns.\n"),
     337                 "Zephyr messages be no wider than 70 columns.\n");
    294338
    295339  OWLVAR_INT( "aim_ignorelogin_timer" /* %OwlVarStub */, 15,
     
    298342              "AIM login before allowing the receipt of AIM login notifications.\n"
    299343              "By default this is set to 15.  If you would like to view login\n"
    300               "notifications of buddies as soon as you login, set it to 0 instead."),
     344              "notifications of buddies as soon as you login, set it to 0 instead.");
    301345
    302346             
     
    311355                   owl_variable_typewinsize_set,
    312356                   NULL /* use default for get */
    313                    ),
     357                   );
    314358
    315359  OWLVAR_INT( "typewindelta" /* %OwlVarStub */, 0,
     
    321365           "typewinsize to 1.\n\n"
    322366           "This works a lot better with a non-default scrollmode;\n"
    323            "try :set scrollmode pagedcenter.\n"),
     367           "try :set scrollmode pagedcenter.\n");
    324368
    325369  OWLVAR_ENUM( "scrollmode" /* %OwlVarStub */, OWL_SCROLLMODE_NORMAL,
     
    350394               "                 the screen will be paged up or down and\n"
    351395               "                 the cursor will be near the center.\n",
    352                "normal,top,neartop,center,paged,pagedcenter" ),
     396               "normal,top,neartop,center,paged,pagedcenter" );
    353397
    354398  OWLVAR_BOOL( "narrow-related" /* %OwlVarStub:narrow_related */, 1,
    355399               "Make smartnarrow use broader filters",
    356                "Causes smartfiler to narrow to messages \"related\" to \n"
     400               "Causes smartfilter to narrow to messages \"related\" to \n"
    357401               "the current message, as well as ones to the same place.\n\n"
    358402               "for Zephyr, this controls whether to narrow to e.g. class-help or\n"
    359403               "class-help.d alone, or to related-class-help, which includes\n"
    360                "help, unhelp, help.d, etc.\n\nDefault is true (include unclasses, etc.).\n" ),
     404               "help, unhelp, help.d, etc.\n\nDefault is true (include unclasses, etc.).\n" );
    361405
    362406  OWLVAR_BOOL( "_followlast" /* %OwlVarStub */, 0,
     
    365409               "continue to follow the last message if this is set.\n"
    366410               "Note that this is currently risky as you might accidentally\n"
    367                "delete a message right as it came in.\n" ),
     411               "delete a message right as it came in.\n" );
    368412
    369413  OWLVAR_STRING_FULL( "default_exposure" /* %OwlVarStub */, "",
     
    374418                      "~/.zephyr.vars.\n"
    375419                      "See the description of exposure for the values this can be.",
    376                       NULL, owl_variable_default_exposure_set, owl_variable_default_exposure_get ),
     420                      NULL, owl_variable_default_exposure_set, owl_variable_default_exposure_get );
    377421
    378422  OWLVAR_STRING_FULL( "exposure" /* %OwlVarStub */, "",
     
    430474                      "                     personal subscriptions will be entered for the\n"
    431475                      "                     user.\n",
    432                       NULL, owl_variable_exposure_set, NULL /* use default for get */ ),
    433 
    434   /* This MUST be last... */
    435   { NULL, 0, NULL, 0, NULL, NULL, NULL, NULL,
    436     NULL, NULL, NULL, NULL, NULL, NULL }
    437 
    438   };
    439 
    440   int ret = owl_variable_dict_add_from_list(vd, variables_to_init);
    441   owl_variable *var;
    442   for (var = variables_to_init; var->name != NULL; var++)
    443     owl_variable_cleanup(var);
    444   return ret;
     476                      NULL, owl_variable_exposure_set, NULL /* use default for get */ );
    445477}
    446478
     
    452484/* commonly useful */
    453485
    454 int owl_variable_int_validate_gt0(const owl_variable *v, const void *newval)
    455 {
    456   if (newval == NULL) return(0);
    457   else if (*(const int*)newval < 1) return(0);
    458   else return (1);
    459 }
    460 
    461 int owl_variable_int_validate_positive(const owl_variable *v, const void *newval)
    462 {
    463   if (newval == NULL) return(0);
    464   else if (*(const int*)newval < 0) return(0);
    465   else return (1);
     486int owl_variable_int_validate_gt0(const owl_variable *v, int newval)
     487{
     488  return !(newval < 1);
     489}
     490
     491int owl_variable_int_validate_positive(const owl_variable *v, int newval)
     492{
     493  return !(newval < 0);
    466494}
    467495
    468496/* typewinsize */
    469 int owl_variable_typewinsize_set(owl_variable *v, const void *newval)
     497int owl_variable_typewinsize_set(owl_variable *v, int newval)
    470498{
    471499  int rv;
     
    476504
    477505/* debug (cache value in g->debug) */
    478 int owl_variable_debug_set(owl_variable *v, const void *newval)
    479 {
    480   if (newval && (*(const int*)newval == 1 || *(const int*)newval == 0)) {
    481     g.debug = *(const int*)newval;
     506int owl_variable_debug_set(owl_variable *v, bool newval)
     507{
     508  g.debug = newval;
     509  return owl_variable_bool_set_default(v, newval);
     510}
     511
     512/* When 'aaway' is changed, need to notify the AIM server */
     513int owl_variable_aaway_set(owl_variable *v, bool newval)
     514{
     515  if (newval) {
     516    owl_aim_set_awaymsg(owl_global_get_aaway_msg(&g));
     517  } else {
     518    owl_aim_set_awaymsg("");
    482519  }
    483520  return owl_variable_bool_set_default(v, newval);
    484521}
    485522
    486 /* When 'aaway' is changed, need to notify the AIM server */
    487 int owl_variable_aaway_set(owl_variable *v, const void *newval)
    488 {
    489   if (newval) {
    490     if (*(const int*)newval == 1) {
    491       owl_aim_set_awaymsg(owl_global_get_aaway_msg(&g));
    492     } else if (*(const int*)newval == 0) {
    493       owl_aim_set_awaymsg("");
    494     }
    495   }
    496   return owl_variable_bool_set_default(v, newval);
    497 }
    498 
    499 int owl_variable_colorztext_set(owl_variable *v, const void *newval)
     523int owl_variable_colorztext_set(owl_variable *v, bool newval)
    500524{
    501525  int ret = owl_variable_bool_set_default(v, newval);
     
    510534}
    511535
    512 int owl_variable_pseudologins_set(owl_variable *v, const void *newval)
     536int owl_variable_pseudologins_set(owl_variable *v, bool newval)
    513537{
    514538  static guint timer = 0;
    515539  if (newval) {
    516     if (*(const int*)newval == 1) {
    517       owl_function_zephyr_buddy_check(0);
    518       if (timer == 0) {
    519         timer = g_timeout_add_seconds(180, owl_zephyr_buddycheck_timer, NULL);
    520       }
    521     } else {
    522       if (timer != 0) {
    523         g_source_remove(timer);
    524         timer = 0;
    525       }
     540    owl_function_zephyr_buddy_check(0);
     541    if (timer == 0) {
     542      timer = g_timeout_add_seconds(180, owl_zephyr_buddycheck_timer, NULL);
     543    }
     544  } else {
     545    if (timer != 0) {
     546      g_source_remove(timer);
     547      timer = 0;
    526548    }
    527549  }
     
    531553/* note that changing the value of this will clobber
    532554 * any user setting of this */
    533 int owl_variable_disable_ctrl_d_set(owl_variable *v, const void *newval)
    534 {
    535   if (newval && !owl_context_is_startup(owl_global_get_context(&g))) {
    536     if (*(const int*)newval == 2) {
     555int owl_variable_disable_ctrl_d_set(owl_variable *v, int newval)
     556{
     557  if (!owl_context_is_startup(owl_global_get_context(&g))) {
     558    if (newval == 2) {
    537559      owl_function_command_norv("bindkey editmulti C-d command edit:delete-next-char");
    538     } else if (*(const int*)newval == 1) {
     560    } else if (newval == 1) {
    539561      owl_function_command_norv("bindkey editmulti C-d command edit:done-or-delete");
    540562    } else {
     
    542564    }
    543565  } 
    544   return owl_variable_int_set_default(v, newval); 
    545 }
    546 
    547 int owl_variable_tty_set(owl_variable *v, const void *newval)
     566  return owl_variable_int_set_default(v, newval);
     567}
     568
     569int owl_variable_tty_set(owl_variable *v, const char *newval)
    548570{
    549571  owl_zephyr_set_locationinfo(g_get_host_name(), newval);
    550   return(owl_variable_string_set_default(v, newval));
    551 }
    552 
    553 int owl_variable_default_exposure_set(owl_variable *v, const void *newval)
     572  return owl_variable_string_set_default(v, newval);
     573}
     574
     575int owl_variable_default_exposure_set(owl_variable *v, const char *newval)
    554576{
    555577  return owl_zephyr_set_default_exposure(newval);
    556578}
    557579
    558 const void *owl_variable_default_exposure_get(const owl_variable *v)
     580const char *owl_variable_default_exposure_get(const owl_variable *v)
    559581{
    560582  return owl_zephyr_get_default_exposure();
    561583}
    562584
    563 int owl_variable_exposure_set(owl_variable *v, const void *newval)
     585int owl_variable_exposure_set(owl_variable *v, const char *newval)
    564586{
    565587  int ret = owl_zephyr_set_exposure(newval);
     
    573595/**************************************************************************/
    574596
    575 int owl_variable_dict_setup(owl_vardict *vd) {
     597void owl_variable_dict_setup(owl_vardict *vd) {
    576598  owl_dict_create(vd);
    577   return owl_variable_add_defaults(vd);
    578 }
    579 
    580 int owl_variable_dict_add_from_list(owl_vardict *vd, owl_variable *variables_to_init)
    581 {
    582   owl_variable *var, *cur;
    583   for (var = variables_to_init; var->name != NULL; var++) {
    584     cur = g_new(owl_variable, 1);
    585     *cur = *var;
    586     /* strdup all the strings so we can delete them consistently. */
    587     cur->name = g_strdup(var->name);
    588     cur->summary = g_strdup(var->summary);
    589     cur->description = g_strdup(var->description);
    590     switch (cur->type) {
    591     case OWL_VARIABLE_OTHER:
    592       cur->set_fn(cur, cur->pval_default);
    593       break;
    594     case OWL_VARIABLE_STRING:
    595       if (!cur->validate_fn)
    596         cur->validate_fn = owl_variable_string_validate_default;
    597       if (!cur->set_fn)
    598         cur->set_fn = owl_variable_string_set_default;
    599       if (!cur->set_fromstring_fn)
    600         cur->set_fromstring_fn = owl_variable_string_set_fromstring_default;
    601       if (!cur->get_fn)
    602         cur->get_fn = owl_variable_get_default;
    603       if (!cur->get_tostring_fn)
    604         cur->get_tostring_fn = owl_variable_string_get_tostring_default;     
    605       if (!cur->delete_fn)
    606         cur->delete_fn = owl_variable_delete_default;
    607       cur->pval_default = g_strdup(var->pval_default);
    608       cur->set_fn(cur, cur->pval_default);
    609       break;
    610     case OWL_VARIABLE_BOOL:
    611       if (!cur->validate_fn)
    612         cur->validate_fn = owl_variable_bool_validate_default;
    613       if (!cur->set_fn)
    614         cur->set_fn = owl_variable_bool_set_default;
    615       if (!cur->set_fromstring_fn)
    616         cur->set_fromstring_fn = owl_variable_bool_set_fromstring_default;
    617       if (!cur->get_fn)
    618         cur->get_fn = owl_variable_get_default;
    619       if (!cur->get_tostring_fn)
    620         cur->get_tostring_fn = owl_variable_bool_get_tostring_default;     
    621       if (!cur->delete_fn)
    622         cur->delete_fn = owl_variable_delete_default;
    623       cur->val = g_new(int, 1);
    624       cur->set_fn(cur, &cur->ival_default);
    625       break;
    626     case OWL_VARIABLE_INT:
    627       if (!cur->validate_fn)
    628         cur->validate_fn = owl_variable_int_validate_default;
    629       if (!cur->set_fn)
    630         cur->set_fn = owl_variable_int_set_default;
    631       if (!cur->set_fromstring_fn)
    632         cur->set_fromstring_fn = owl_variable_int_set_fromstring_default;
    633       if (!cur->get_fn)
    634         cur->get_fn = owl_variable_get_default;
    635       if (!cur->get_tostring_fn)
    636         cur->get_tostring_fn = owl_variable_int_get_tostring_default;     
    637       if (!cur->delete_fn)
    638         cur->delete_fn = owl_variable_delete_default;
    639       cur->val = g_new(int, 1);
    640       cur->set_fn(cur, &cur->ival_default);
    641       break;
    642     default:
    643       fprintf(stderr, "owl_variable_setup: invalid variable type\n");
    644       return(-2);
    645     }
    646     owl_dict_insert_element(vd, cur->name, cur, NULL);
    647   }
    648   return 0;
     599  owl_variable_add_defaults(vd);
     600}
     601
     602CALLER_OWN GClosure *owl_variable_make_closure(owl_variable *v,
     603                                               GCallback fn,
     604                                               GClosureMarshal marshal) {
     605  GClosure *closure = g_cclosure_new_swap(fn, v, NULL);
     606  g_closure_set_marshal(closure,marshal);
     607  g_closure_ref(closure);
     608  g_closure_sink(closure);
     609  return closure;
    649610}
    650611
    651612void owl_variable_dict_add_variable(owl_vardict * vardict,
    652613                                    owl_variable * var) {
     614  char *oldvalue = NULL;
     615  owl_variable *oldvar = owl_variable_get_var(vardict, var->name);
     616  /* Save the old value as a string. */
     617  if (oldvar) {
     618    oldvalue = owl_variable_get_tostring(oldvar);
     619  }
    653620  owl_dict_insert_element(vardict, var->name, var, (void (*)(void *))owl_variable_delete);
    654 }
    655 
    656 CALLER_OWN owl_variable *owl_variable_newvar(const char *name, const char *summary, const char *description)
    657 {
    658   owl_variable * var = g_new0(owl_variable, 1);
     621  /* Restore the old value. */
     622  if (oldvalue) {
     623    owl_variable_set_fromstring(var, oldvalue, 0);
     624    g_free(oldvalue);
     625  }
     626}
     627
     628static owl_variable *owl_variable_newvar(int type, const char *name, const char *summary, const char *description, const char *validsettings) {
     629  owl_variable *var = g_new0(owl_variable, 1);
     630  var->type = type;
    659631  var->name = g_strdup(name);
    660632  var->summary = g_strdup(summary);
    661633  var->description = g_strdup(description);
     634  var->validsettings = g_strdup(validsettings);
    662635  return var;
    663636}
    664637
    665 void owl_variable_update(owl_variable *var, const char *summary, const char *desc) {
    666   g_free(var->summary);
    667   var->summary = g_strdup(summary);
    668   g_free(var->description);
    669   var->description = g_strdup(desc);
    670 }
    671 
    672 void owl_variable_dict_newvar_string(owl_vardict *vd, const char *name, const char *summ, const char *desc, const char *initval)
    673 {
    674   owl_variable *old = owl_variable_get_var(vd, name);
    675   if (old && owl_variable_get_type(old) == OWL_VARIABLE_STRING) {
    676     owl_variable_update(old, summ, desc);
    677     g_free(old->pval_default);
    678     old->pval_default = g_strdup(initval);
    679   } else {
    680     owl_variable * var = owl_variable_newvar(name, summ, desc);
    681     var->type = OWL_VARIABLE_STRING;
    682     var->validsettings = "<string>";
    683     var->pval_default = g_strdup(initval);
    684     var->set_fn = owl_variable_string_set_default;
    685     var->set_fromstring_fn = owl_variable_string_set_fromstring_default;
    686     var->get_fn = owl_variable_get_default;
    687     var->get_tostring_fn = owl_variable_string_get_tostring_default;
    688     var->delete_fn = owl_variable_delete_default;
    689     var->set_fn(var, initval);
    690     owl_variable_dict_add_variable(vd, var);
    691   }
    692 }
    693 
    694 void owl_variable_dict_newvar_int(owl_vardict *vd, const char *name, const char *summ, const char *desc, int initval)
    695 {
    696   owl_variable *old = owl_variable_get_var(vd, name);
    697   if (old && owl_variable_get_type(old) == OWL_VARIABLE_INT) {
    698     owl_variable_update(old, summ, desc);
    699     old->ival_default = initval;
    700   } else {
    701     owl_variable * var = owl_variable_newvar(name, summ, desc);
    702     var->type = OWL_VARIABLE_INT;
    703     var->validsettings = "<int>";
    704     var->ival_default = initval;
    705     var->validate_fn = owl_variable_int_validate_default;
    706     var->set_fn = owl_variable_int_set_default;
    707     var->set_fromstring_fn = owl_variable_int_set_fromstring_default;
    708     var->get_fn = owl_variable_get_default;
    709     var->get_tostring_fn = owl_variable_int_get_tostring_default;
    710     var->delete_fn = owl_variable_delete_default;
    711     var->val = g_new(int, 1);
    712     var->set_fn(var, &initval);
    713     owl_variable_dict_add_variable(vd, var);
    714   }
    715 }
    716 
    717 void owl_variable_dict_newvar_bool(owl_vardict *vd, const char *name, const char *summ, const char *desc, int initval)
    718 {
    719   owl_variable *old = owl_variable_get_var(vd, name);
    720   if (old && owl_variable_get_type(old) == OWL_VARIABLE_BOOL) {
    721     owl_variable_update(old, summ, desc);
    722     old->ival_default = initval;
    723   } else {
    724     owl_variable * var = owl_variable_newvar(name, summ, desc);
    725     var->type = OWL_VARIABLE_BOOL;
    726     var->validsettings = "on,off";
    727     var->ival_default = initval;
    728     var->validate_fn = owl_variable_bool_validate_default;
    729     var->set_fn = owl_variable_bool_set_default;
    730     var->set_fromstring_fn = owl_variable_bool_set_fromstring_default;
    731     var->get_fn = owl_variable_get_default;
    732     var->get_tostring_fn = owl_variable_bool_get_tostring_default;
    733     var->delete_fn = owl_variable_delete_default;
    734     var->val = g_new(int, 1);
    735     var->set_fn(var, &initval);
    736     owl_variable_dict_add_variable(vd, var);
    737   }
     638static void owl_variable_dict_newvar_int_full(owl_vardict *vd, const char *name, int default_val, const char *summary, const char *description, const char *validsettings, validate_int_t validate_fn, set_int_t set_fn, get_int_t get_fn)
     639{
     640  owl_variable *var = owl_variable_newvar(OWL_VARIABLE_INT, name, summary,
     641                                          description, validsettings);
     642  var->takes_on_off = false;
     643  var->get_fn = G_CALLBACK(get_fn ? get_fn : owl_variable_int_get_default);
     644  var->set_fn = G_CALLBACK(set_fn ? set_fn : owl_variable_int_set_default);
     645  var->validate_fn = G_CALLBACK(validate_fn ? validate_fn : owl_variable_int_validate_default);
     646
     647  var->get_tostring_fn = owl_variable_make_closure(
     648      var, G_CALLBACK(owl_variable_int_get_tostring_default),
     649      g_cclosure_user_marshal_STRING__VOID);
     650  var->set_fromstring_fn = owl_variable_make_closure(
     651      var, G_CALLBACK(owl_variable_int_set_fromstring_default),
     652      g_cclosure_user_marshal_INT__STRING);
     653
     654  g_value_init(&var->val, G_TYPE_INT);
     655  owl_variable_set_int(var, default_val);
     656
     657  var->default_str = owl_variable_get_tostring(var);
     658  owl_variable_dict_add_variable(vd, var);
     659}
     660
     661void owl_variable_dict_newvar_int(owl_vardict *vd, const char *name, int default_val, const char *summary, const char *description) {
     662  owl_variable_dict_newvar_int_full(vd, name, default_val, summary, description,
     663                                    "<int>", NULL, NULL, NULL);
     664}
     665
     666static void owl_variable_dict_newvar_bool_full(owl_vardict *vd, const char *name, bool default_val, const char *summary, const char *description, validate_bool_t validate_fn, set_bool_t set_fn, get_bool_t get_fn)
     667{
     668  owl_variable *var = owl_variable_newvar(OWL_VARIABLE_BOOL, name, summary,
     669                                          description, "on,off");
     670  var->takes_on_off = true;
     671  var->get_fn = G_CALLBACK(get_fn ? get_fn : owl_variable_bool_get_default);
     672  var->set_fn = G_CALLBACK(set_fn ? set_fn : owl_variable_bool_set_default);
     673  var->validate_fn = G_CALLBACK(validate_fn ? validate_fn : owl_variable_bool_validate_default);
     674
     675  var->get_tostring_fn = owl_variable_make_closure(
     676      var, G_CALLBACK(owl_variable_bool_get_tostring_default),
     677      g_cclosure_user_marshal_STRING__VOID);
     678  var->set_fromstring_fn = owl_variable_make_closure(
     679      var, G_CALLBACK(owl_variable_bool_set_fromstring_default),
     680      g_cclosure_user_marshal_INT__STRING);
     681
     682  g_value_init(&var->val, G_TYPE_BOOLEAN);
     683  owl_variable_set_bool(var, default_val);
     684
     685  var->default_str = owl_variable_get_tostring(var);
     686  owl_variable_dict_add_variable(vd, var);
     687}
     688
     689void owl_variable_dict_newvar_bool(owl_vardict *vd, const char *name, bool default_val, const char *summary, const char *description) {
     690  owl_variable_dict_newvar_bool_full(vd, name, default_val, summary, description,
     691                                     NULL, NULL, NULL);
     692}
     693
     694static void owl_variable_dict_newvar_string_full(owl_vardict *vd, const char *name, const char *default_val, const char *summary, const char *description, const char *validsettings, validate_string_t validate_fn, set_string_t set_fn, get_string_t get_fn)
     695{
     696  owl_variable *var = owl_variable_newvar(OWL_VARIABLE_STRING, name, summary,
     697                                          description, validsettings);
     698  var->takes_on_off = false;
     699  var->get_fn = G_CALLBACK(get_fn ? get_fn : owl_variable_string_get_default);
     700  var->set_fn = G_CALLBACK(set_fn ? set_fn : owl_variable_string_set_default);
     701  var->validate_fn = G_CALLBACK(validate_fn ? validate_fn : owl_variable_string_validate_default);
     702
     703  var->get_tostring_fn = owl_variable_make_closure(
     704      var, G_CALLBACK(owl_variable_string_get_tostring_default),
     705      g_cclosure_user_marshal_STRING__VOID);
     706  var->set_fromstring_fn = owl_variable_make_closure(
     707      var, G_CALLBACK(owl_variable_string_set_fromstring_default),
     708      g_cclosure_user_marshal_INT__STRING);
     709
     710  g_value_init(&var->val, G_TYPE_STRING);
     711  owl_variable_set_string(var, default_val);
     712
     713  var->default_str = owl_variable_get_tostring(var);
     714  owl_variable_dict_add_variable(vd, var);
     715}
     716
     717void owl_variable_dict_newvar_string(owl_vardict *vd, const char *name, const char *default_val, const char *summary, const char *description) {
     718  owl_variable_dict_newvar_string_full(vd, name, default_val, summary, description,
     719                                       "<string>", NULL, NULL, NULL);
     720}
     721
     722void owl_variable_dict_newvar_path(owl_vardict *vd, const char *name, const char *default_val, const char *summary, const char *description) {
     723  owl_variable_dict_newvar_string_full(vd, name, default_val, summary, description,
     724                                       "<path>", NULL, NULL, NULL);
     725}
     726
     727static void owl_variable_dict_newvar_enum_full(owl_vardict *vd, const char *name, int default_val, const char *summary, const char *description, const char *validsettings, validate_int_t validate_fn, set_int_t set_fn, get_int_t get_fn)
     728{
     729  owl_variable *var = owl_variable_newvar(OWL_VARIABLE_INT, name, summary,
     730                                          description, validsettings);
     731  var->takes_on_off = false;
     732  var->get_fn = G_CALLBACK(get_fn ? get_fn : owl_variable_int_get_default);
     733  var->set_fn = G_CALLBACK(set_fn ? set_fn : owl_variable_int_set_default);
     734  var->validate_fn = G_CALLBACK(validate_fn ? validate_fn : owl_variable_enum_validate);
     735
     736  var->get_tostring_fn = owl_variable_make_closure(
     737      var, G_CALLBACK(owl_variable_enum_get_tostring),
     738      g_cclosure_user_marshal_STRING__VOID);
     739  var->set_fromstring_fn = owl_variable_make_closure(
     740      var, G_CALLBACK(owl_variable_enum_set_fromstring),
     741      g_cclosure_user_marshal_INT__STRING);
     742
     743  g_value_init(&var->val, G_TYPE_INT);
     744  owl_variable_set_int(var, default_val);
     745
     746  var->default_str = owl_variable_get_tostring(var);
     747  owl_variable_dict_add_variable(vd, var);
     748}
     749
     750void owl_variable_dict_newvar_enum(owl_vardict *vd, const char *name, int default_val, const char *summary, const char *description, const char *validset) {
     751  owl_variable_dict_newvar_enum_full(vd, name, default_val, summary, description,
     752                                     validset, NULL, NULL, NULL);
     753}
     754
     755void owl_variable_dict_newvar_other(owl_vardict *vd, const char *name, const char *summary, const char *description, const char *validsettings, bool takes_on_off, GClosure *get_tostring_fn, GClosure *set_fromstring_fn)
     756{
     757  owl_variable *var = owl_variable_newvar(OWL_VARIABLE_OTHER, name, summary,
     758                                          description, validsettings);
     759  var->takes_on_off = takes_on_off;
     760
     761  var->get_tostring_fn = g_closure_ref(get_tostring_fn);
     762  g_closure_sink(get_tostring_fn);
     763
     764  var->set_fromstring_fn = g_closure_ref(set_fromstring_fn);
     765  g_closure_sink(set_fromstring_fn);
     766
     767  var->default_str = owl_variable_get_tostring(var);
     768
     769  /* Note: this'll overwrite any existing variable of that name, even a C one,
     770     but it's consistent with previous behavior and commands. */
     771  owl_variable_dict_add_variable(vd, var);
    738772}
    739773
     
    747781}
    748782
    749 void owl_variable_cleanup(owl_variable *v)
    750 {
    751   if (v->delete_fn) v->delete_fn(v);
     783void owl_variable_delete(owl_variable *v)
     784{
    752785  g_free(v->name);
    753786  g_free(v->summary);
    754787  g_free(v->description);