File: irc.pm

package info (click to toggle)
liburi-perl 5.34-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 984 kB
  • sloc: perl: 4,001; makefile: 4
file content (142 lines) | stat: -rw-r--r-- 3,732 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package URI::irc;  # draft-butcher-irc-url-04

use strict;
use warnings;

our $VERSION = '5.34';

use parent 'URI::_login';

use overload (
   '""'     => sub { $_[0]->as_string  },
   '=='     => sub {  URI::_obj_eq(@_) },
   '!='     => sub { !URI::_obj_eq(@_) },
   fallback => 1,
);

sub default_port { 6667 }

#   ircURL   = ircURI "://" location "/" [ entity ] [ flags ] [ options ]
#   ircURI   = "irc" / "ircs"
#   location = [ authinfo "@" ] hostport
#   authinfo = [ username ] [ ":" password ]
#   username = *( escaped / unreserved )
#   password = *( escaped / unreserved ) [ ";" passtype ]
#   passtype = *( escaped / unreserved )
#   entity   = [ "#" ] *( escaped / unreserved )
#   flags    = ( [ "," enttype ] [ "," hosttype ] )
#           /= ( [ "," hosttype ] [ "," enttype ] )
#   enttype  = "," ( "isuser" / "ischannel" )
#   hosttype = "," ( "isserver" / "isnetwork" )
#   options  = "?" option *( "&" option )
#   option   = optname [ "=" optvalue ]
#   optname  = *( ALPHA / "-" )
#   optvalue = optparam *( "," optparam )
#   optparam = *( escaped / unreserved )

# XXX: Technically, passtype is part of the protocol, but is rarely used and
# not defined in the RFC beyond the URL ABNF.

# Starting the entity with /# is okay per spec, but it needs to be encoded to
# %23 for the URL::_generic::path operations to parse correctly.
sub _init {
    my $class = shift;
    my $self = $class->SUPER::_init(@_);
    $$self =~ s|^((?:[^:/?\#]+:)?(?://[^/?\#]*)?)/\#|$1/%23|s;
    $self;
}

# Return the /# form, since this is most common for channel names.
sub path {
    my $self = shift;
    my ($new) = @_;
    $new =~ s|^/\#|/%23| if (@_ && defined $new);
    my $val = $self->SUPER::path(@_ ? $new : ());
    $val =~ s|^/%23|/\#|;
    $val;
}
sub path_query {
    my $self = shift;
    my ($new) = @_;
    $new =~ s|^/\#|/%23| if (@_ && defined $new);
    my $val = $self->SUPER::path_query(@_ ? $new : ());
    $val =~ s|^/%23|/\#|;
    $val;
}
sub as_string {
    my $self = shift;
    my $val = $self->SUPER::as_string;
    $val =~ s|^((?:[^:/?\#]+:)?(?://[^/?\#]*)?)/%23|$1/\#|s;
    $val;
}

sub entity {
    my $self = shift;

    my $path = $self->path;
    $path =~ s|^/||;
    my ($entity, @flags) = split /,/, $path;

    if (@_) {
        my $new = shift;
        $new = '' unless defined $new;
        $self->path( '/'.join(',', $new, @flags) );
    }

    return unless length $entity;
    $entity;
}

sub flags {
    my $self = shift;

    my $path = $self->path;
    $path =~ s|^/||;
    my ($entity, @flags) = split /,/, $path;

    if (@_) {
        $self->path( '/'.join(',', $entity, @_) );
    }

    @flags;
}

sub options { shift->query_form(@_) }

sub canonical {
    my $self = shift;
    my $other = $self->SUPER::canonical;

    # Clean up the flags
    my $path = $other->path;
    $path =~ s|^/||;
    my ($entity, @flags) = split /,/, $path;

    my @clean =
        map { $_ eq 'isnick' ? 'isuser' : $_ }  # convert isnick->isuser
        map { lc }
        # NOTE: Allow flags from draft-mirashi-url-irc-01 as well
        grep { /^(?:is(?:user|channel|server|network|nick)|need(?:pass|key))$/i }
        @flags
    ;

    # Only allow the first type of each category, per the Butcher draft
    my ($enttype)  = grep { /^is(?:user|channel)$/   } @clean;
    my ($hosttype) = grep { /^is(?:server|network)$/ } @clean;
    my @others     = grep { /^need(?:pass|key)$/ }     @clean;

    my @new = (
        $enttype  ? $enttype  : (),
        $hosttype ? $hosttype : (),
        @others,
    );

    unless (join(',', @new) eq join(',', @flags)) {
        $other = $other->clone if $other == $self;
        $other->path( '/'.join(',', $entity, @new) );
    }

    $other;
}

1;