source: perl/lib/BarnOwl/Message/Zephyr.pm @ d2ba33c

Last change on this file since d2ba33c was d2ba33c, checked in by Jason Gross <jasongross9@gmail.com>, 7 years ago
Use g_utf8_casefold and g_utf8_normalize We define a convenience function compat_casefold in util.c for reuse in filters.
  • Property mode set to 100644
File size: 7.6 KB
Line 
1use strict;
2use warnings;
3
4package BarnOwl::Message::Zephyr;
5
6use constant WEBZEPHYR_PRINCIPAL => "daemon/webzephyr.mit.edu";
7use constant WEBZEPHYR_CLASS     => "webzephyr";
8use constant WEBZEPHYR_OPCODE    => "webzephyr";
9
10use base qw( BarnOwl::Message );
11
12sub strip_realm {
13    my $sender = shift;
14    my $realm = BarnOwl::zephyr_getrealm();
15    $sender =~ s/\@\Q$realm\E$//;
16    return $sender;
17}
18
19sub principal_realm {
20    my $principal = shift;
21    my ($user, $realm) = split(/@/,$principal);
22    return $realm;
23}
24
25sub casefold_principal {
26    my $principal = shift;
27    # split the principal right after the final @, without eating any
28    # characters; this way, we always get at least '@' in $user
29    my ($user, $realm) = split(/(?<=@)(?=[^@]+$)/, $principal);
30    return lc($user) . uc($realm);
31}
32
33sub login_type {
34    return (shift->zsig eq "") ? "(PSEUDO)" : "";
35}
36
37sub login_extra {
38    my $m = shift;
39    return undef if (!$m->is_loginout);
40    my $s = lc($m->host);
41    $s .= " " . $m->login_tty if defined $m->login_tty;
42    return $s;
43}
44
45sub long_sender {
46    my $m = shift;
47    return $m->zsig;
48}
49
50sub context {
51    return shift->class;
52}
53
54sub subcontext {
55    return shift->instance;
56}
57
58sub login_tty {
59    my ($m) = @_;
60    return undef if (!$m->is_loginout);
61    return undef if (!defined($m->fields));
62    return $m->fields->[2];
63}
64
65sub login_host {
66    my ($m) = @_;
67    return undef if (!$m->is_loginout);
68    return undef if (!defined($m->fields));
69    return $m->fields->[0];
70}
71
72sub zwriteline  { return shift->{"zwriteline"}; }
73
74sub is_ping     { return (lc(shift->opcode) eq "ping"); }
75
76sub is_mail {
77    my ($m) = @_;
78    return ((lc($m->class) eq "mail") && $m->is_private);
79}
80
81sub pretty_sender {
82    my ($m) = @_;
83    return strip_realm($m->sender);
84}
85
86sub pretty_recipient {
87    my ($m) = @_;
88    return strip_realm($m->recipient);
89}
90
91# Portion of the reply command that preserves the context
92sub context_reply_cmd {
93    my $mclass = shift;
94    my $minstance = shift;
95    my @class;
96    if (lc($mclass) ne "message") {
97        @class = ('-c', $mclass);
98    }
99    my @instance;
100    if (lc($minstance) ne "personal") {
101        @instance = ('-i', $minstance);
102    }
103    return (@class, @instance);
104}
105
106sub personal_context {
107    my ($m) = @_;
108    return BarnOwl::quote(context_reply_cmd($m->class, $m->instance));
109}
110
111sub short_personal_context {
112    my ($m) = @_;
113    if(lc($m->class) eq 'message')
114    {
115        if(lc($m->instance) eq 'personal')
116        {
117            return '';
118        } else {
119            return $m->instance;
120        }
121    } else {
122        return $m->class;
123    }
124}
125
126# These are arguably zephyr-specific
127sub class       { return shift->{"class"}; }
128sub instance    { return shift->{"instance"}; }
129sub realm       { return shift->{"realm"}; }
130sub opcode      { return shift->{"opcode"}; }
131sub host        { return shift->{"hostname"}; }
132sub hostname    { return shift->{"hostname"}; }
133sub header      { return shift->{"header"}; }
134sub auth        { return shift->{"auth"}; }
135sub fields      { return shift->{"fields"}; }
136sub zsig        { return shift->{"zsig"}; }
137
138sub zephyr_cc {
139    my $self = shift;
140    return $1 if $self->body =~ /^\s*cc:\s+([^\n]+)/i;
141    return undef;
142}
143
144sub zephyr_cc_without_recipient {
145    my $self = shift;
146    my $recipient = lc(strip_realm($self->recipient));
147    my $cc = $self->zephyr_cc;
148    return grep { lc(strip_realm($_)) ne $recipient } split(/\s+/, $cc) if defined $cc;
149    return ();
150}
151
152sub replycmd {
153    my $self = shift;
154    my $sender = shift;
155    $sender = 0 unless defined $sender;
156    my ($class, $instance, $to, $cc);
157    if($self->is_outgoing) {
158        return $self->{zwriteline};
159    }
160
161    if($sender && $self->opcode eq WEBZEPHYR_OPCODE) {
162        $class = WEBZEPHYR_CLASS;
163        $instance = $self->pretty_sender;
164        $instance =~ s/-webzephyr$//;
165        $to = WEBZEPHYR_PRINCIPAL;
166    } elsif($self->class eq WEBZEPHYR_CLASS
167            && $self->is_loginout) {
168        $class = WEBZEPHYR_CLASS;
169        $instance = $self->instance;
170        $to = WEBZEPHYR_PRINCIPAL;
171    } elsif($self->is_loginout) {
172        $class = 'MESSAGE';
173        $instance = 'PERSONAL';
174        $to = $self->sender;
175    } elsif($sender && !$self->is_private) {
176        # Possible future feature: (Optionally?) include the class and/or
177        # instance of the message being replied to in the instance of the
178        # outgoing personal reply
179        $class = 'MESSAGE';
180        $instance = 'PERSONAL';
181        $to = $self->sender;
182    } else {
183        $class = $self->class;
184        $instance = $self->instance;
185        if ($self->recipient eq '' || $self->recipient =~ /^@/) {
186            $to = $self->recipient;
187        } else {
188            $to = $self->sender;
189            $cc = $self->zephyr_cc();
190        }
191    }
192
193    my @cmd;
194    if(lc $self->opcode eq 'crypt' and ( not $sender or $self->is_private)) {
195        # Responses to zcrypted messages should be zcrypted, so long as we
196        # aren't switching to personals
197        @cmd = ('zcrypt');
198    } else {
199        @cmd = ('zwrite');
200    }
201
202    push @cmd, context_reply_cmd($class, $instance);
203
204    if ($to ne '') {
205        $to = strip_realm($to);
206        if (defined $cc and not $sender) {
207            my @cc = grep /^[^-]/, ($to, split /\s+/, $cc);
208            my %cc = map {$_ => 1} @cc;
209            # this isn't quite right - it doesn't strip off the
210            # user if the message was addressed to them by fully qualified
211            # name
212            delete $cc{strip_realm(BarnOwl::zephyr_getsender())};
213            @cc = keys %cc;
214
215            my $sender_realm = principal_realm($self->sender);
216            if (BarnOwl::zephyr_getrealm() ne $sender_realm) {
217                @cc = map {
218                    if($_ !~ /@/) {
219                       "${_}\@${sender_realm}";
220                    } else {
221                        $_;
222                    }
223                } @cc;
224            }
225            push @cmd, '-C', @cc;
226        } else {
227            if(BarnOwl::getvar('smartstrip') eq 'on') {
228                $to = BarnOwl::zephyr_smartstrip_user($to);
229            }
230            push @cmd, $to;
231        }
232    }
233    return BarnOwl::quote(@cmd);
234}
235
236sub replysendercmd {
237    my $self = shift;
238    return $self->replycmd(1);
239}
240
241# Logging
242sub log_header {
243    my ($m) = @_;
244    my $class = $m->class;
245    my $instance = $m->instance;
246    my $opcode = $m->opcode;
247    my $timestr = $m->time;
248    my $host = $m->host;
249    my $sender = $m->pretty_sender;
250    my $zsig = $m->zsig;
251    my $rtn = "Class: $class Instance: $instance";
252    $rtn .= " Opcode: $opcode" unless !defined $opcode || $opcode eq '';
253    $rtn .= "\nTime: $timestr Host: $host"
254          . "\nFrom: $zsig <$sender>";
255    return $rtn;
256}
257
258sub log_filenames {
259    my ($m) = @_;
260    my @filenames = ();
261    if ($m->is_personal) {
262        @filenames = $m->zephyr_cc_without_recipient;
263    }
264    if ($m->is_incoming) {
265        if ($m->is_personal) {
266            push @filenames, $m->sender;
267        } else {
268            my $realm = '';
269            $realm .= '@' . $m->realm if $m->realm ne BarnOwl::zephyr_getrealm();
270            return (BarnOwl::compat_casefold($m->class) . uc($realm));
271        }
272    } else {
273        push @filenames, $m->recipient;
274    }
275    return map { casefold_principal(BarnOwl::zephyr_smartstrip_user(strip_realm($_))) } @filenames;
276}
277
278sub log_to_class_file {
279    my ($m) = @_;
280    return !$m->is_personal;
281}
282
283sub log_path {
284    my ($m) = @_;
285    if ($m->log_to_class_file) {
286        return BarnOwl::getvar('classlogpath');
287    } else {
288        return BarnOwl::getvar('logpath');
289    }
290}
291
292sub should_log {
293    my ($m) = @_;
294    if ($m->log_to_class_file) {
295        return BarnOwl::getvar('classlogging') eq 'on';
296    } else {
297        return BarnOwl::getvar('logging') eq 'on';
298    }
299}
300
3011;
Note: See TracBrowser for help on using the repository browser.