use warnings; use strict; package BarnOwl::Module::Unicorn; our $VERSION = '0.3'; # your one-stop shop for dealing with magical unclasses and tangentially # related goodies # hacked from a thing ltchin gave me # she says it's from wings or horkley, idk # --bpchen 2015-11-3 # now supports adding clauses to narrow --bpchen 2016-2-2 # quotemeta added --bpchen 2016-2-27 # the versatile unireply added --bpchen 2016-2-27 # this part is mostly copied from Alias.pm, due to nelhage(?) my $cfg = BarnOwl::get_config_dir(); my $mapfile = "$cfg/unclassmap"; my %unclassmap; my %unclasslistmap; my %rootclassmap; if (-r $mapfile) { open(my $fh, "<:encoding(UTF-8)", $mapfile) or die("Unable to read $mapfile$!\n"); while(defined(my $line = <$fh>)) { next if $line =~ /^\s+#/; next if $line =~ /^\s+$/; my @components = split(/\s+/, $line); next unless @components; my $cls0 = shift @components; $rootclassmap{$cls0} = $cls0; $unclasslistmap{$cls0} = [@components]; my $clsprev = shift @components; $rootclassmap{lc($clsprev)} = $cls0; $unclassmap{lc($cls0)} = $clsprev; while (@components) { my $clsnext = shift @components; $unclassmap{lc($clsprev)} = $clsnext; $rootclassmap{lc($clsnext)} = $cls0; $clsprev = $clsnext; } } close($fh); } sub get_unclass { my $cls = shift; my $uncls = $unclassmap{lc($cls)}; return defined($uncls) ? $uncls : "un$cls"; } sub make_unireply { my $operations = shift; my $z = BarnOwl::getcurmsg(); my ($class, $instance, $to, $cc); return unless $z->is_zephyr; $class = $z->class; $instance = $z->instance; $to = $z->recipient; $cc = $z->zephyr_cc(); if($to eq '*' || $to eq '') { $to = ''; } elsif($to !~ /^@/) { $to = $z->sender; } my $cmd; if(lc $z->opcode eq 'crypt') { $cmd = 'zcrypt'; } else { $cmd = 'zwrite'; } my $do_un = sub { if (lc $class eq 'message') { $instance = "un$instance"; } else { $class = get_unclass($class); } }; for (split //, $operations) { if ($_ eq 'u') { $do_un->(); } elsif (/\d/) { my $n = $_; for (1..$n) { $do_un->(); } } elsif ($_ eq 'd') { $instance = "$instance.d"; } elsif ($_ eq 'q') { $instance = "$instance.q"; } elsif ($_ eq 't') { $instance = "$instance.ttants"; } elsif ($_ eq 'p') { $instance = "$instance.pwants"; } elsif ($_ eq 'z' || $_ eq 's') { $instance = "$instance.zsig"; } } if (lc $class eq 'message') { $cmd .= " -i " . BarnOwl::quote($instance); } else { $cmd .= " -c " . BarnOwl::quote($class); if (lc $instance ne 'personal') { $cmd .= " -i " . BarnOwl::quote($instance); } } if ($to ne '') { $to = BarnOwl::Message::Zephyr::strip_realm($to); if(BarnOwl::getvar('smartstrip') eq 'on') { $to = BarnOwl::zephyr_smartstrip_user($to); } $cmd .= " $to"; } return $cmd; } sub make_unreply { return make_unireply('u'); } sub unreply { BarnOwl::command(make_unreply()); } sub unireply { BarnOwl::command(make_unireply($_[1])); } sub start_unreply { BarnOwl::command("start-command " . make_unreply()); } sub discuss { BarnOwl::command(make_unireply('d')); } sub uninarrow { shift; my $narrow_instance = 0; if (@_ && $_[0] == '-i') { shift; $narrow_instance = 1; } my $z = BarnOwl::getcurmsg(); my ($class, $instance, $to, $cc); return unless $z->is_zephyr; $class = $z->class; $instance = $z->instance; $to = $z->recipient; $cc = $z->zephyr_cc(); my $rootclass = $rootclassmap{$class}; my @cs = (); my $delegate_flag = 1; # do we delegate to smartnarrow? if (defined($rootclass)) { @cs = @{$unclasslistmap{$rootclass}}; $delegate_flag = 0; } elsif (@_) { $rootclass = $class; $delegate_flag = 0; } if ($delegate_flag) { if ($narrow_instance) { BarnOwl::command('smartnarrow -i'); } else { BarnOwl::command('smartnarrow'); } } else { my @class_clauses = ('class', '^(un)*' . quotemeta($rootclass) . '(\\.d)*$'); for (@cs) { push @class_clauses, 'or', 'class', '^' . quotemeta($_) . '$'; } my $filter_name = "uninarrowed-class-$rootclass"; my @clauses; if ($narrow_instance) { @clauses = ('(', @class_clauses, qw{) and instance}, '^(un)*' . quotemeta($instance) . '(\\.d)*$'); $filter_name .= "-instance-$instance"; } else { @clauses = @class_clauses; } # BarnOwl::popless_text(BarnOwl::quote(qw(view -d), '(', @clauses, ')', @_)); BarnOwl::command(BarnOwl::quote('filter', $filter_name, '(', @clauses, ')', @_)); BarnOwl::command(BarnOwl::quote('view', $filter_name)); } } BarnOwl::new_command (unreply => \&unreply, {summary => "like reply, but prepends un- to the class or instance magically", } ); BarnOwl::new_command ('start-unreply' => \&start_unreply, {summary => "like reply -e, but prepends un- to the class or instance magically", } ); BarnOwl::new_command (unireply => \&unireply, {summary => "like reply, but takes a magic string and does magic things to the class/instance", } ); BarnOwl::new_command (discuss => \&discuss, {summary => "like reply, but appends .d to the instance", } ); BarnOwl::new_command (uninarrow => \&uninarrow, {summary => "like smartnarrow, but also narrows special unclasses magically", } ); 1;