| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Net::SDP; | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | ################ | 
| 4 |  |  |  |  |  |  | # | 
| 5 |  |  |  |  |  |  | # Net::SDP - Session Description Protocol (rfc2327) | 
| 6 |  |  |  |  |  |  | # | 
| 7 |  |  |  |  |  |  | # Nicholas J Humfrey | 
| 8 |  |  |  |  |  |  | # njh@cpan.org | 
| 9 |  |  |  |  |  |  | # | 
| 10 |  |  |  |  |  |  | # See the bottom of this file for the POD documentation. | 
| 11 |  |  |  |  |  |  | # | 
| 12 |  |  |  |  |  |  | # All parsing and generating of SDP data | 
| 13 |  |  |  |  |  |  | # is delt with in this file | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  |  | 
| 16 | 5 |  |  | 5 |  | 52268 | use strict; | 
|  | 5 |  |  |  |  | 12 |  | 
|  | 5 |  |  |  |  | 246 |  | 
| 17 | 5 |  |  | 5 |  | 29 | use vars qw/$VERSION/; | 
|  | 5 |  |  |  |  | 9 |  | 
|  | 5 |  |  |  |  | 215 |  | 
| 18 |  |  |  |  |  |  |  | 
| 19 | 5 |  |  | 5 |  | 4320 | use Net::SDP::Media; | 
|  | 5 |  |  |  |  | 12 |  | 
|  | 5 |  |  |  |  | 151 |  | 
| 20 | 5 |  |  | 5 |  | 3768 | use Net::SDP::Time; | 
|  | 5 |  |  |  |  | 13 |  | 
|  | 5 |  |  |  |  | 167 |  | 
| 21 | 5 |  |  | 5 |  | 5179 | use Sys::Hostname; | 
|  | 5 |  |  |  |  | 7541 |  | 
|  | 5 |  |  |  |  | 279 |  | 
| 22 | 5 |  |  | 5 |  | 5133 | use Net::hostent; | 
|  | 5 |  |  |  |  | 28729 |  | 
|  | 5 |  |  |  |  | 66 |  | 
| 23 | 5 |  |  | 5 |  | 305 | use Carp; | 
|  | 5 |  |  |  |  | 7 |  | 
|  | 5 |  |  |  |  | 40522 |  | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | $VERSION="0.07"; | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | sub new { | 
| 30 | 4 |  |  | 4 | 1 | 2328 | my $class = shift; | 
| 31 | 4 |  |  |  |  | 15 | my ($data) = @_; | 
| 32 |  |  |  |  |  |  |  | 
| 33 | 4 |  |  |  |  | 79 | my $self = {'v'=>'0', | 
| 34 |  |  |  |  |  |  | 'session'=> { | 
| 35 |  |  |  |  |  |  | 'o_uname' => '', | 
| 36 |  |  |  |  |  |  | 'o_sess_id' => 0, | 
| 37 |  |  |  |  |  |  | 'o_sess_vers' => 0, | 
| 38 |  |  |  |  |  |  | 'o_net_type' => '', | 
| 39 |  |  |  |  |  |  | 'o_addr_type' => '', | 
| 40 |  |  |  |  |  |  | 'o_address' => '', | 
| 41 |  |  |  |  |  |  | 'p' => [], | 
| 42 |  |  |  |  |  |  | 'e' => [], | 
| 43 |  |  |  |  |  |  | 'a' => {} | 
| 44 |  |  |  |  |  |  | }, | 
| 45 |  |  |  |  |  |  | 'media'=>[], | 
| 46 |  |  |  |  |  |  | 'time'=>[] | 
| 47 |  |  |  |  |  |  | }; | 
| 48 | 4 |  |  |  |  | 14 | bless $self, $class; | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | # Parse data if we are passed some | 
| 52 | 4 | 50 |  |  |  | 20 | if (defined $data) { | 
| 53 | 0 | 0 |  |  |  | 0 | unless ($self->parse( $data )) { | 
| 54 |  |  |  |  |  |  | # Failed to parse | 
| 55 | 0 |  |  |  |  | 0 | return undef; | 
| 56 |  |  |  |  |  |  | } | 
| 57 |  |  |  |  |  |  | } else { | 
| 58 |  |  |  |  |  |  | # Use sane defaults | 
| 59 | 4 |  | 50 |  |  | 59 | $self->{'session'}->{'o_uname'} = $ENV{'USER'} || '-'; | 
| 60 | 4 |  |  |  |  | 26 | $self->{'session'}->{'o_sess_id'} = Net::SDP::Time::_ntptime(); | 
| 61 | 4 |  |  |  |  | 21 | $self->{'session'}->{'o_sess_vers'} = Net::SDP::Time::_ntptime(); | 
| 62 | 4 |  |  |  |  | 135 | $self->{'session'}->{'o_net_type'} = 'IN'; | 
| 63 | 4 |  |  |  |  | 14 | $self->{'session'}->{'o_addr_type'} = 'IP4'; | 
| 64 |  |  |  |  |  |  |  | 
| 65 | 4 |  |  |  |  | 23 | my $hostname = hostname(); | 
| 66 | 4 | 50 |  |  |  | 83 | if (defined $hostname) { | 
| 67 | 4 | 50 |  |  |  | 25 | if (my $h = gethost($hostname)) { | 
| 68 | 4 |  |  |  |  | 4148 | $self->{'session'}->{'o_address'} = $h->name(); | 
| 69 |  |  |  |  |  |  | } | 
| 70 |  |  |  |  |  |  | } | 
| 71 |  |  |  |  |  |  | } | 
| 72 |  |  |  |  |  |  |  | 
| 73 | 4 |  |  |  |  | 76 | return $self; | 
| 74 |  |  |  |  |  |  | } | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | # Try and work out what the source is | 
| 77 |  |  |  |  |  |  | sub parse { | 
| 78 | 1 |  |  | 1 | 1 | 6 | my $self = shift; | 
| 79 | 1 |  |  |  |  | 2 | my ($source) = @_; | 
| 80 |  |  |  |  |  |  |  | 
| 81 | 1 | 50 |  |  |  | 4 | if (@_ == 1) { | 
|  |  | 0 |  |  |  |  |  | 
| 82 |  |  |  |  |  |  |  | 
| 83 | 1 | 50 |  |  |  | 8 | if (ref $source eq 'Net::SAP::Packet') { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 84 |  |  |  |  |  |  | # It is a SAP packet | 
| 85 | 0 | 0 |  |  |  | 0 | if ($source->payload_type() ne 'application/sdp') { | 
| 86 | 0 |  |  |  |  | 0 | carp "Payload type of Net::SAP::Packet is not application/sdp."; | 
| 87 | 0 |  |  |  |  | 0 | return 0; | 
| 88 |  |  |  |  |  |  | } | 
| 89 | 0 |  |  |  |  | 0 | return $self->parse_data( $source->payload() ); | 
| 90 |  |  |  |  |  |  |  | 
| 91 |  |  |  |  |  |  | } elsif ($source =~ /^v=0/) { | 
| 92 |  |  |  |  |  |  | # Looks like start of SDP file | 
| 93 | 1 |  |  |  |  | 5 | return $self->parse_data( $source ); | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | } elsif ($source =~ /^\w+:/) { | 
| 96 |  |  |  |  |  |  | # Looks like a URL | 
| 97 | 0 |  |  |  |  | 0 | return $self->parse_url( $source ); | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | } elsif ($source eq '-') { | 
| 100 |  |  |  |  |  |  | # Parse STDIN | 
| 101 | 0 |  |  |  |  | 0 | return $self->parse_stdin(); | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | } elsif ($source ne '') { | 
| 104 |  |  |  |  |  |  | # Assume it is a filename | 
| 105 | 0 |  |  |  |  | 0 | return $self->parse_file( $source ); | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | } else { | 
| 108 | 0 |  |  |  |  | 0 | carp "Failed to parse empty string."; | 
| 109 | 0 |  |  |  |  | 0 | return 0; | 
| 110 |  |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | } elsif (@_ == 0) { | 
| 113 | 0 |  |  |  |  | 0 | return $self->parse_stdin(); | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  | } else { | 
| 116 | 0 |  |  |  |  | 0 | croak "Too many parameters for parse()"; | 
| 117 |  |  |  |  |  |  | } | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | } | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  | sub parse_file { | 
| 122 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 123 | 0 |  |  |  |  | 0 | my ($filename) = @_; | 
| 124 |  |  |  |  |  |  |  | 
| 125 | 0 | 0 |  |  |  | 0 | open(SDP, $filename) or croak "can't open SDP file ($filename): $!"; | 
| 126 | 0 |  |  |  |  | 0 | local $/ = undef;  # slurp full file | 
| 127 | 0 |  |  |  |  | 0 | my $data = ; | 
| 128 | 0 |  |  |  |  | 0 | close (SDP); | 
| 129 |  |  |  |  |  |  |  | 
| 130 | 0 |  |  |  |  | 0 | return $self->parse_data( $data ); | 
| 131 |  |  |  |  |  |  | } | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | sub parse_url { | 
| 134 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 135 | 0 |  |  |  |  | 0 | my ($url) = @_; | 
| 136 |  |  |  |  |  |  |  | 
| 137 | 0 |  |  |  |  | 0 | eval "use LWP::Simple"; | 
| 138 | 0 | 0 |  |  |  | 0 | croak "Couldn't fetch URL because LWP::Simple is unavailable." if ($@); | 
| 139 |  |  |  |  |  |  |  | 
| 140 | 0 | 0 |  |  |  | 0 | my $data = LWP::Simple::get($url) or | 
| 141 |  |  |  |  |  |  | croak "Failed to fetch the URL '$url' with LWP: $!\n"; | 
| 142 |  |  |  |  |  |  |  | 
| 143 | 0 |  |  |  |  | 0 | return $self->parse_data( $data ); | 
| 144 |  |  |  |  |  |  | } | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  | sub parse_stdin { | 
| 147 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 148 |  |  |  |  |  |  |  | 
| 149 | 0 |  |  |  |  | 0 | local $/ = undef;  # slurp STDIN | 
| 150 | 0 |  |  |  |  | 0 | my $data = <>; | 
| 151 |  |  |  |  |  |  |  | 
| 152 | 0 |  |  |  |  | 0 | return $self->parse_data( $data ); | 
| 153 |  |  |  |  |  |  | } | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  |  | 
| 156 |  |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  |  | 
| 159 |  |  |  |  |  |  | sub parse_data { | 
| 160 | 1 |  |  | 1 | 1 | 2 | my $self = shift; | 
| 161 | 1 |  |  |  |  | 2 | my ($data) = @_; | 
| 162 | 1 | 50 |  |  |  | 10 | croak "Missing SDP data parameter.\n" unless (defined $data); | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | # Undefine defaults | 
| 165 | 1 |  |  |  |  | 2 | undef $self->{'v'}; | 
| 166 | 1 |  |  |  |  | 4 | undef $self->{'session'}->{'s'}; | 
| 167 | 1 |  |  |  |  | 2 | undef $self->{'session'}->{'o_sess_id'}; | 
| 168 | 1 |  |  |  |  | 2 | undef $self->{'session'}->{'o_sess_vers'}; | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | # Sections of sdp file: 'session', 'media' | 
| 172 | 1 |  |  |  |  | 185 | my $section = "session"; | 
| 173 |  |  |  |  |  |  |  | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  | # Split the file up into an array of its lines | 
| 176 | 1 |  |  |  |  | 18 | my @lines = split(/[\r\n]+/, $data); | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  |  | 
| 179 | 1 |  |  |  |  | 5 | while (my $line = shift(@lines)) { | 
| 180 | 12 |  |  |  |  | 109 | my ($field, $value) = ($line =~ /^(\w)=(.*?)\s*$/); | 
| 181 | 12 | 50 |  |  |  | 56 | if ($field eq '') { | 
| 182 | 0 |  |  |  |  | 0 | carp "Failed to parse line of SDP data: $line\n"; | 
| 183 | 0 |  |  |  |  | 0 | next; | 
| 184 |  |  |  |  |  |  | } | 
| 185 |  |  |  |  |  |  |  | 
| 186 |  |  |  |  |  |  | # Ignore empty values | 
| 187 | 12 | 50 |  |  |  | 21 | next if ($value eq ''); | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  |  | 
| 190 |  |  |  |  |  |  | ## Session description | 
| 191 | 12 | 100 |  |  |  | 22 | if ($section eq 'session') { | 
| 192 |  |  |  |  |  |  |  | 
| 193 | 10 | 100 | 100 |  |  | 80 | if ($field eq 'v') { | 
|  |  | 100 | 66 |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 194 |  |  |  |  |  |  |  | 
| 195 | 1 | 50 |  |  |  | 4 | $self->_parse_v( $value ) || return 0; | 
| 196 |  |  |  |  |  |  |  | 
| 197 |  |  |  |  |  |  | } elsif ($field eq 'm') { | 
| 198 |  |  |  |  |  |  |  | 
| 199 |  |  |  |  |  |  | # Move on to the media section | 
| 200 | 1 |  |  |  |  | 1 | $section = 'media'; | 
| 201 |  |  |  |  |  |  |  | 
| 202 |  |  |  |  |  |  | } elsif ($field eq 't') { | 
| 203 |  |  |  |  |  |  |  | 
| 204 | 1 |  |  |  |  | 11 | my $time = new Net::SDP::Time( $value ); | 
| 205 |  |  |  |  |  |  |  | 
| 206 | 1 |  |  |  |  | 3 | push( @{$self->{'time'}}, $time ); | 
|  | 1 |  |  |  |  | 9 |  | 
| 207 |  |  |  |  |  |  |  | 
| 208 |  |  |  |  |  |  | } elsif ($field eq 'r') { | 
| 209 |  |  |  |  |  |  |  | 
| 210 |  |  |  |  |  |  | # Add to last time descriptor | 
| 211 | 0 | 0 |  |  |  | 0 | unless ( $self->{'time'}->[-1] ) { | 
| 212 | 0 |  |  |  |  | 0 | carp "No previous 't' parameter to associate 'r' with: $line\n"; | 
| 213 | 0 |  |  |  |  | 0 | next; | 
| 214 |  |  |  |  |  |  | } | 
| 215 |  |  |  |  |  |  |  | 
| 216 | 0 |  |  |  |  | 0 | $self->{'time'}->[-1]->_parse_r($value); | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | } elsif ($field eq 'o') { | 
| 219 |  |  |  |  |  |  |  | 
| 220 | 1 |  |  |  |  | 4 | $self->_parse_o( $value ); | 
| 221 |  |  |  |  |  |  |  | 
| 222 |  |  |  |  |  |  | } elsif ($field eq 'p' || $field eq 'e') { | 
| 223 |  |  |  |  |  |  |  | 
| 224 |  |  |  |  |  |  | # Phone and email can have more than one value | 
| 225 | 2 |  |  |  |  | 3 | push( @{$self->{'session'}->{$field}}, $value ); | 
|  | 2 |  |  |  |  | 5 |  | 
| 226 |  |  |  |  |  |  |  | 
| 227 |  |  |  |  |  |  | } elsif ($field eq 'a' || $field eq 'b') { | 
| 228 |  |  |  |  |  |  |  | 
| 229 |  |  |  |  |  |  | # More than one value is allowed | 
| 230 | 1 |  |  |  |  | 6 | _add_attribute( $self->{'session'}, $field, $value ); | 
| 231 |  |  |  |  |  |  |  | 
| 232 |  |  |  |  |  |  | } else { | 
| 233 |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  | # Single value | 
| 235 | 3 |  |  |  |  | 9 | $self->{'session'}->{$field} = $value; | 
| 236 |  |  |  |  |  |  | } | 
| 237 |  |  |  |  |  |  | } | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | ## Media description | 
| 241 | 12 | 100 |  |  |  | 42 | if ($section eq 'media') { | 
| 242 |  |  |  |  |  |  |  | 
| 243 | 3 | 100 |  |  |  | 203 | if ($field eq 'm') { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 244 | 1 |  |  |  |  | 9 | my $media = new Net::SDP::Media( $value ); | 
| 245 |  |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | # Copy accross connection information for easier access | 
| 247 | 1 | 50 |  |  |  | 4 | if (defined $self->{'session'}->{'c'}) { | 
| 248 | 0 |  |  |  |  | 0 | $media->_parse_c( $self->{'session'}->{'c'} ); | 
| 249 |  |  |  |  |  |  | } | 
| 250 | 1 |  |  |  |  | 2 | push( @{$self->{'media'}}, $media ); | 
|  | 1 |  |  |  |  | 4 |  | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | } elsif ($field =~ /a|b/) { | 
| 253 |  |  |  |  |  |  |  | 
| 254 |  |  |  |  |  |  | # XXXXXX Check array exists? XXXXXX | 
| 255 | 0 |  |  |  |  | 0 | _add_attribute( $self->{'media'}->[-1], $field, $value ); | 
| 256 |  |  |  |  |  |  |  | 
| 257 |  |  |  |  |  |  | } elsif ($field =~ /c/) { | 
| 258 |  |  |  |  |  |  |  | 
| 259 | 1 |  |  |  |  | 2 | my $media = $self->{'media'}->[-1]; | 
| 260 | 1 |  |  |  |  | 65 | $media->_parse_c( $value ); | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | } else { | 
| 263 | 1 |  |  |  |  | 9 | $self->{'media'}->[-1]->{$field} = $value; | 
| 264 |  |  |  |  |  |  | } | 
| 265 |  |  |  |  |  |  |  | 
| 266 |  |  |  |  |  |  | } | 
| 267 |  |  |  |  |  |  |  | 
| 268 |  |  |  |  |  |  | } | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  |  | 
| 271 |  |  |  |  |  |  | # Ensure we have the required elements | 
| 272 | 1 |  |  |  |  | 11 | $self->_validate_self(); | 
| 273 |  |  |  |  |  |  |  | 
| 274 |  |  |  |  |  |  |  | 
| 275 |  |  |  |  |  |  | # Success | 
| 276 | 1 |  |  |  |  | 4 | return 1; | 
| 277 |  |  |  |  |  |  | } | 
| 278 |  |  |  |  |  |  |  | 
| 279 |  |  |  |  |  |  |  | 
| 280 |  |  |  |  |  |  | # Ensure we have the right session elements | 
| 281 |  |  |  |  |  |  | sub _validate_self { | 
| 282 | 1 |  |  | 1 |  | 3 | my $self = shift; | 
| 283 | 1 |  |  |  |  | 1 | my $session = $self->{'session'}; | 
| 284 |  |  |  |  |  |  |  | 
| 285 |  |  |  |  |  |  | # The following elements are required | 
| 286 | 1 | 50 |  |  |  | 4 | if (!defined $self->{'v'}) { | 
| 287 | 0 |  |  |  |  | 0 | carp "Invalid SDP file: Missing version field"; | 
| 288 | 0 |  |  |  |  | 0 | return 1; | 
| 289 |  |  |  |  |  |  | } | 
| 290 | 1 | 50 |  |  |  | 4 | if (!defined $session->{'o_sess_id'}) { | 
| 291 | 0 |  |  |  |  | 0 | carp "Invalid SDP file: Missing origin session ID field"; | 
| 292 | 0 |  |  |  |  | 0 | return 1; | 
| 293 |  |  |  |  |  |  | } | 
| 294 | 1 | 50 |  |  |  | 3 | if (!defined $session->{'o_sess_vers'}) { | 
| 295 | 0 |  |  |  |  | 0 | carp "Invalid SDP file: Missing origin version field"; | 
| 296 | 0 |  |  |  |  | 0 | return 1; | 
| 297 |  |  |  |  |  |  | } | 
| 298 | 1 | 50 |  |  |  | 3 | if (!defined $session->{'s'}) { | 
| 299 | 0 |  |  |  |  | 0 | carp "Invalid SDP file: Missing session name field"; | 
| 300 | 0 |  |  |  |  | 0 | return 1; | 
| 301 |  |  |  |  |  |  | } | 
| 302 |  |  |  |  |  |  |  | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | # We should have a Time Description... | 
| 305 | 1 | 50 |  |  |  | 3 | if (!exists $self->{'time'}->[0]) { | 
| 306 | 0 |  |  |  |  | 0 | carp "Invalid SDP file: Session is missing required time discription"; | 
| 307 |  |  |  |  |  |  |  | 
| 308 |  |  |  |  |  |  | # Make it valid :-/ | 
| 309 | 0 |  |  |  |  | 0 | $self->{'time'}->[0] = new Net::SDP::Time(); | 
| 310 |  |  |  |  |  |  | } | 
| 311 |  |  |  |  |  |  |  | 
| 312 |  |  |  |  |  |  | # Everything is ok :) | 
| 313 | 1 |  |  |  |  | 2 | return 0; | 
| 314 |  |  |  |  |  |  | } | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  | sub generate { | 
| 317 | 1 |  |  | 1 | 1 | 6 | my $self=shift; | 
| 318 | 1 |  |  |  |  | 2 | my $session = $self->{'session'}; | 
| 319 | 1 |  |  |  |  | 3 | my $sdp = ''; | 
| 320 |  |  |  |  |  |  |  | 
| 321 |  |  |  |  |  |  | # The order of the fields must be as stated in the RFC | 
| 322 | 1 |  |  |  |  | 4 | $sdp .= $self->_generate_v(); | 
| 323 | 1 |  |  |  |  | 4 | $sdp .= $self->_generate_o(); | 
| 324 | 1 |  |  |  |  | 4 | $sdp .= _generate_lines($session, 's', 0 ); | 
| 325 | 1 |  |  |  |  | 4 | $sdp .= _generate_lines($session, 'i', 1 ); | 
| 326 | 1 |  |  |  |  | 3 | $sdp .= _generate_lines($session, 'u', 1 ); | 
| 327 | 1 |  |  |  |  | 3 | $sdp .= _generate_lines($session, 'e', 1 ); | 
| 328 | 1 |  |  |  |  | 3 | $sdp .= _generate_lines($session, 'p', 1 ); | 
| 329 |  |  |  |  |  |  | #c=	- I don't like having c lines here ! | 
| 330 |  |  |  |  |  |  | #	The module will put c= lines in the media description | 
| 331 | 1 |  |  |  |  | 3 | $sdp .= _generate_lines($session, 'b', 1 ); | 
| 332 |  |  |  |  |  |  |  | 
| 333 |  |  |  |  |  |  |  | 
| 334 |  |  |  |  |  |  | # Time Descriptions | 
| 335 | 1 | 50 |  |  |  | 2 | if (scalar(@{$self->{'time'}})==0) { | 
|  | 1 |  |  |  |  | 5 |  | 
| 336 |  |  |  |  |  |  | # At least one is required | 
| 337 | 0 |  |  |  |  | 0 | warn "Missing Time description"; | 
| 338 | 0 |  |  |  |  | 0 | return undef; | 
| 339 |  |  |  |  |  |  | } | 
| 340 | 1 |  |  |  |  | 3 | foreach my $time ( @{$self->{'time'}} ) { | 
|  | 1 |  |  |  |  | 2 |  | 
| 341 | 1 |  |  |  |  | 6 | $sdp .= $time->_generate_t(); | 
| 342 |  |  |  |  |  |  | #$sdp .= _generate_lines($time, 'z', 1 ); | 
| 343 | 1 |  |  |  |  | 5 | $sdp .= $time->_generate_r(); | 
| 344 |  |  |  |  |  |  | } | 
| 345 |  |  |  |  |  |  |  | 
| 346 | 1 |  |  |  |  | 3 | $sdp .= _generate_lines($session, 'k', 1 ); | 
| 347 | 1 |  |  |  |  | 3 | $sdp .= _generate_lines($session, 'a', 1 ); | 
| 348 |  |  |  |  |  |  |  | 
| 349 |  |  |  |  |  |  |  | 
| 350 |  |  |  |  |  |  | # Media Descriptions | 
| 351 | 1 |  |  |  |  | 3 | foreach my $media ( @{$self->{'media'}} ) { | 
|  | 1 |  |  |  |  | 3 |  | 
| 352 | 1 |  |  |  |  | 6 | $sdp .= $media->_generate_m(); | 
| 353 | 1 |  |  |  |  | 3 | $sdp .= _generate_lines($media, 'i', 1 ); | 
| 354 |  |  |  |  |  |  | # 'c' is non-optional because we dont have one | 
| 355 |  |  |  |  |  |  | # in the session description | 
| 356 | 1 |  |  |  |  | 5 | $sdp .= $media->_generate_c(); | 
| 357 | 1 |  |  |  |  | 4 | $sdp .= _generate_lines($media, 'b', 1 ); | 
| 358 | 1 |  |  |  |  | 3 | $sdp .= _generate_lines($media, 'k', 1 ); | 
| 359 | 1 |  |  |  |  | 15 | $sdp .= _generate_lines($media, 'a', 1 ); | 
| 360 |  |  |  |  |  |  | } | 
| 361 |  |  |  |  |  |  |  | 
| 362 |  |  |  |  |  |  | # Return the SDP description we just generated | 
| 363 | 1 |  |  |  |  | 11 | return $sdp; | 
| 364 |  |  |  |  |  |  | } | 
| 365 |  |  |  |  |  |  |  | 
| 366 |  |  |  |  |  |  | sub _generate_lines { | 
| 367 | 12 |  |  | 12 |  | 19 | my ($hashref, $field, $optional) = @_; | 
| 368 | 12 |  |  |  |  | 16 | my $lines = ''; | 
| 369 |  |  |  |  |  |  |  | 
| 370 | 12 | 100 | 66 |  |  | 57 | if (exists $hashref->{$field} and | 
| 371 |  |  |  |  |  |  | defined $hashref->{$field}) { | 
| 372 | 8 | 100 |  |  |  | 32 | if (ref $hashref->{$field} eq 'ARRAY') { | 
|  |  | 100 |  |  |  |  |  | 
| 373 | 2 |  |  |  |  | 3 | foreach( @{$hashref->{$field}} ) { | 
|  | 2 |  |  |  |  | 6 |  | 
| 374 | 4 |  |  |  |  | 12 | $lines .= "$field=$_\n"; | 
| 375 |  |  |  |  |  |  | } | 
| 376 |  |  |  |  |  |  | } elsif (ref $hashref->{$field} eq 'HASH') { | 
| 377 | 2 |  |  |  |  | 3 | foreach my $att_field ( sort keys %{$hashref->{$field}} ) { | 
|  | 2 |  |  |  |  | 14 |  | 
| 378 | 2 |  |  |  |  | 5 | my $attrib = $hashref->{$field}->{$att_field}; | 
| 379 | 2 | 50 |  |  |  | 6 | if (ref $attrib eq 'ARRAY') { | 
| 380 | 2 |  |  |  |  | 3 | foreach my $att_value (@{$attrib}) { | 
|  | 2 |  |  |  |  | 4 |  | 
| 381 | 2 |  |  |  |  | 11 | $lines .= "$field=$att_field:$att_value\n"; | 
| 382 |  |  |  |  |  |  | } | 
| 383 |  |  |  |  |  |  | } else { | 
| 384 | 0 |  |  |  |  | 0 | $lines .= "$field=$att_field\n"; | 
| 385 |  |  |  |  |  |  | } | 
| 386 |  |  |  |  |  |  | } | 
| 387 |  |  |  |  |  |  | } else { | 
| 388 | 4 |  |  |  |  | 10 | $lines = $field.'='.$hashref->{$field}."\n"; | 
| 389 |  |  |  |  |  |  | } | 
| 390 |  |  |  |  |  |  | } else { | 
| 391 | 4 | 50 |  |  |  | 8 | if (!$optional) { | 
| 392 | 0 |  |  |  |  | 0 | warn "Non-optional field '$field' missing"; | 
| 393 |  |  |  |  |  |  | } | 
| 394 |  |  |  |  |  |  | } | 
| 395 |  |  |  |  |  |  |  | 
| 396 | 12 |  |  |  |  | 27 | return $lines; | 
| 397 |  |  |  |  |  |  | } | 
| 398 |  |  |  |  |  |  |  | 
| 399 |  |  |  |  |  |  |  | 
| 400 |  |  |  |  |  |  | sub _parse_o { | 
| 401 | 1 |  |  | 1 |  | 2 | my $self = shift; | 
| 402 | 1 |  |  |  |  | 2 | my $session = $self->{'session'}; | 
| 403 | 1 |  |  |  |  | 9 | my ($o) = @_; | 
| 404 |  |  |  |  |  |  |  | 
| 405 | 1 |  |  |  |  | 12 | ($session->{'o_uname'}, | 
| 406 |  |  |  |  |  |  | $session->{'o_sess_id'}, | 
| 407 |  |  |  |  |  |  | $session->{'o_sess_vers'}, | 
| 408 |  |  |  |  |  |  | $session->{'o_net_type'}, | 
| 409 |  |  |  |  |  |  | $session->{'o_addr_type'}, | 
| 410 |  |  |  |  |  |  | $session->{'o_address'}) = split(/\s/, $o); | 
| 411 |  |  |  |  |  |  |  | 
| 412 |  |  |  |  |  |  | # Success | 
| 413 | 1 |  |  |  |  | 3 | return 1; | 
| 414 |  |  |  |  |  |  | } | 
| 415 |  |  |  |  |  |  |  | 
| 416 |  |  |  |  |  |  |  | 
| 417 |  |  |  |  |  |  | sub _generate_o { | 
| 418 | 1 |  |  | 1 |  | 2 | my $self = shift; | 
| 419 | 1 |  |  |  |  | 5 | return "o=".$self->session_origin()."\n"; | 
| 420 |  |  |  |  |  |  | } | 
| 421 |  |  |  |  |  |  |  | 
| 422 |  |  |  |  |  |  |  | 
| 423 |  |  |  |  |  |  | sub _parse_v { | 
| 424 | 1 |  |  | 1 |  | 2 | my $self = shift; | 
| 425 | 1 |  |  |  |  | 3 | $self->{'v'} = shift; | 
| 426 |  |  |  |  |  |  |  | 
| 427 |  |  |  |  |  |  | # Check the version number | 
| 428 | 1 | 50 |  |  |  | 5 | if ($self->{'v'} ne '0') { | 
| 429 | 0 |  |  |  |  | 0 | carp "Unsupported SDP format version number: ".$self->{'v'}; | 
| 430 | 0 |  |  |  |  | 0 | return 0; | 
| 431 |  |  |  |  |  |  | } | 
| 432 |  |  |  |  |  |  |  | 
| 433 |  |  |  |  |  |  | # Success | 
| 434 | 1 |  |  |  |  | 4 | return 1; | 
| 435 |  |  |  |  |  |  | } | 
| 436 |  |  |  |  |  |  |  | 
| 437 |  |  |  |  |  |  |  | 
| 438 |  |  |  |  |  |  | sub _generate_v { | 
| 439 | 1 |  |  | 1 |  | 2 | my $self = shift; | 
| 440 | 1 |  |  |  |  | 2 | return "v=0\n"; | 
| 441 |  |  |  |  |  |  | } | 
| 442 |  |  |  |  |  |  |  | 
| 443 |  |  |  |  |  |  | # hashref - the hash to add the attribute to | 
| 444 |  |  |  |  |  |  | # field - the name of the field - ie 'a' | 
| 445 |  |  |  |  |  |  | # value - the actual attribute | 
| 446 |  |  |  |  |  |  | sub _add_attribute { | 
| 447 | 1 |  |  | 1 |  | 2 | my ($hashref, $field, $value) = @_; | 
| 448 |  |  |  |  |  |  |  | 
| 449 | 1 | 50 |  |  |  | 4 | if (!defined $hashref->{$field}) { | 
| 450 | 0 |  |  |  |  | 0 | $hashref->{$field} = {}; | 
| 451 |  |  |  |  |  |  | } | 
| 452 |  |  |  |  |  |  |  | 
| 453 | 1 | 50 |  |  |  | 14 | if ( my($att_field, $att_value) = ($value =~ /^([\w\-\_]+):(.*)$/) ) { | 
| 454 | 1 |  |  |  |  | 2 | my $fieldref = $hashref->{$field}; | 
| 455 |  |  |  |  |  |  |  | 
| 456 | 1 | 50 |  |  |  | 4 | if (!defined $fieldref->{$att_field}) { | 
| 457 | 1 |  |  |  |  | 3 | $fieldref->{$att_field} = []; | 
| 458 |  |  |  |  |  |  | } | 
| 459 |  |  |  |  |  |  |  | 
| 460 | 1 |  |  |  |  | 2 | push( @{$fieldref->{$att_field}}, $att_value ); | 
|  | 1 |  |  |  |  | 4 |  | 
| 461 |  |  |  |  |  |  |  | 
| 462 |  |  |  |  |  |  | } else { | 
| 463 | 0 |  |  |  |  | 0 | $hashref->{$field}->{$value} = ''; | 
| 464 |  |  |  |  |  |  | } | 
| 465 |  |  |  |  |  |  | } | 
| 466 |  |  |  |  |  |  |  | 
| 467 |  |  |  |  |  |  | sub session_origin { | 
| 468 | 1 |  |  | 1 | 1 | 2 | my $self=shift; | 
| 469 | 1 |  |  |  |  | 2 | my $session = $self->{'session'}; | 
| 470 | 1 |  |  |  |  | 2 | my ($o) = @_; | 
| 471 |  |  |  |  |  |  |  | 
| 472 | 1 | 50 |  |  |  | 4 | $self->_parse_o( $o ) if (defined $o); | 
| 473 |  |  |  |  |  |  |  | 
| 474 | 1 |  |  |  |  | 10 | return  $session->{'o_uname'} .' '. | 
| 475 |  |  |  |  |  |  | $session->{'o_sess_id'} .' '. | 
| 476 |  |  |  |  |  |  | $session->{'o_sess_vers'} .' '. | 
| 477 |  |  |  |  |  |  | $session->{'o_net_type'} .' '. | 
| 478 |  |  |  |  |  |  | $session->{'o_addr_type'} .' '. | 
| 479 |  |  |  |  |  |  | $session->{'o_address'}; | 
| 480 |  |  |  |  |  |  | } | 
| 481 |  |  |  |  |  |  |  | 
| 482 |  |  |  |  |  |  | sub session_origin_username { | 
| 483 | 2 |  |  | 2 | 1 | 561 | my $self=shift; | 
| 484 | 2 |  |  |  |  | 4 | my ($uname) = @_; | 
| 485 | 2 | 100 |  |  |  | 10 | $self->{'session'}->{'o_uname'} = $uname if (defined $uname); | 
| 486 | 2 |  |  |  |  | 9 | return $self->{'session'}->{'o_uname'}; | 
| 487 |  |  |  |  |  |  | } | 
| 488 |  |  |  |  |  |  |  | 
| 489 |  |  |  |  |  |  | sub session_origin_id { | 
| 490 | 2 |  |  | 2 | 1 | 8 | my $self=shift; | 
| 491 | 2 |  |  |  |  | 4 | my ($id) = @_; | 
| 492 | 2 | 100 |  |  |  | 9 | $self->{'session'}->{'o_sess_id'} = $id if (defined $id); | 
| 493 | 2 |  |  |  |  | 8 | return $self->{'session'}->{'o_sess_id'}; | 
| 494 |  |  |  |  |  |  | } | 
| 495 |  |  |  |  |  |  |  | 
| 496 |  |  |  |  |  |  | sub session_origin_version { | 
| 497 | 2 |  |  | 2 | 1 | 7 | my $self=shift; | 
| 498 | 2 |  |  |  |  | 3 | my ($vers) = @_; | 
| 499 | 2 | 100 |  |  |  | 15 | $self->{'session'}->{'o_sess_vers'} = $vers if defined $vers; | 
| 500 | 2 |  |  |  |  | 13 | return $self->{'session'}->{'o_sess_vers'}; | 
| 501 |  |  |  |  |  |  | } | 
| 502 |  |  |  |  |  |  |  | 
| 503 |  |  |  |  |  |  | sub session_origin_net_type { | 
| 504 | 2 |  |  | 2 | 1 | 8 | my $self=shift; | 
| 505 | 2 |  |  |  |  | 4 | my ($net_type) = @_; | 
| 506 | 2 | 100 |  |  |  | 9 | $self->{'session'}->{'o_net_type'} = $net_type if defined $net_type; | 
| 507 | 2 |  |  |  |  | 8 | return $self->{'session'}->{'o_net_type'}; | 
| 508 |  |  |  |  |  |  | } | 
| 509 |  |  |  |  |  |  |  | 
| 510 |  |  |  |  |  |  | sub session_origin_addr_type { | 
| 511 | 2 |  |  | 2 | 1 | 5 | my $self=shift; | 
| 512 | 2 |  |  |  |  | 38 | my ($addr_type) = @_; | 
| 513 | 2 | 100 |  |  |  | 8 | $self->{'session'}->{'o_addr_type'} = $addr_type if defined $addr_type; | 
| 514 | 2 |  |  |  |  | 7 | return $self->{'session'}->{'o_addr_type'}; | 
| 515 |  |  |  |  |  |  | } | 
| 516 |  |  |  |  |  |  |  | 
| 517 |  |  |  |  |  |  | sub session_origin_address { | 
| 518 | 2 |  |  | 2 | 1 | 7 | my $self=shift; | 
| 519 | 2 |  |  |  |  | 11 | my ($addr) = @_; | 
| 520 | 2 | 100 |  |  |  | 7 | $self->{'session'}->{'o_address'} = $addr if defined $addr; | 
| 521 | 2 |  |  |  |  | 8 | return $self->{'session'}->{'o_address'}; | 
| 522 |  |  |  |  |  |  | } | 
| 523 |  |  |  |  |  |  |  | 
| 524 |  |  |  |  |  |  |  | 
| 525 |  |  |  |  |  |  |  | 
| 526 |  |  |  |  |  |  | # Returns a unique identifier for this session | 
| 527 |  |  |  |  |  |  | # | 
| 528 |  |  |  |  |  |  | sub session_identifier { | 
| 529 | 0 |  |  | 0 | 1 | 0 | my $self=shift; | 
| 530 | 0 |  |  |  |  | 0 | my $session = $self->{'session'}; | 
| 531 |  |  |  |  |  |  |  | 
| 532 | 0 |  |  |  |  | 0 | return	$session->{'o_uname'} . | 
| 533 |  |  |  |  |  |  | sprintf("%x",$session->{'o_sess_id'}) . | 
| 534 |  |  |  |  |  |  | $session->{'o_net_type'} . | 
| 535 |  |  |  |  |  |  | $session->{'o_addr_type'} . | 
| 536 |  |  |  |  |  |  | $session->{'o_address'}; | 
| 537 |  |  |  |  |  |  | } | 
| 538 |  |  |  |  |  |  |  | 
| 539 |  |  |  |  |  |  |  | 
| 540 |  |  |  |  |  |  | sub session_name { | 
| 541 | 2 |  |  | 2 | 1 | 6 | my $self=shift; | 
| 542 | 2 |  |  |  |  | 4 | my ($s) = @_; | 
| 543 | 2 | 100 |  |  |  | 10 | $self->{'session'}->{'s'} = $s if defined $s; | 
| 544 | 2 |  |  |  |  | 8 | return $self->{'session'}->{'s'}; | 
| 545 |  |  |  |  |  |  | } | 
| 546 |  |  |  |  |  |  |  | 
| 547 |  |  |  |  |  |  | sub session_info { | 
| 548 | 2 |  |  | 2 | 1 | 8 | my $self=shift; | 
| 549 | 2 |  |  |  |  | 4 | my ($i) = @_; | 
| 550 | 2 | 100 |  |  |  | 9 | $self->{'session'}->{'i'} = $i if defined $i; | 
| 551 | 2 |  |  |  |  | 8 | return $self->{'session'}->{'i'}; | 
| 552 |  |  |  |  |  |  | } | 
| 553 |  |  |  |  |  |  |  | 
| 554 |  |  |  |  |  |  | sub session_uri { | 
| 555 | 2 |  |  | 2 | 1 | 7 | my $self=shift; | 
| 556 | 2 |  |  |  |  | 4 | my ($u) = @_; | 
| 557 | 2 | 100 |  |  |  | 16 | $self->{'session'}->{'u'} = $u if defined $u; | 
| 558 | 2 |  |  |  |  | 8 | return $self->{'session'}->{'u'}; | 
| 559 |  |  |  |  |  |  | } | 
| 560 |  |  |  |  |  |  |  | 
| 561 |  |  |  |  |  |  | sub session_email { | 
| 562 | 2 |  |  | 2 | 1 | 8 | my $self=shift; | 
| 563 | 2 |  |  |  |  | 5 | my ($e) = @_; | 
| 564 | 2 |  |  |  |  | 4 | my $session = $self->{'session'}; | 
| 565 |  |  |  |  |  |  |  | 
| 566 |  |  |  |  |  |  | # An ARRAYREF may be passed to set more than one email address | 
| 567 | 2 | 100 |  |  |  | 19 | if (defined $e) { | 
| 568 | 1 | 50 |  |  |  | 5 | if (ref $e eq 'ARRAY') { | 
| 569 | 1 |  |  |  |  | 3 | $session->{'e'} = $e; | 
| 570 |  |  |  |  |  |  | } else { | 
| 571 | 0 |  |  |  |  | 0 | $session->{'e'} = [ $e ]; | 
| 572 |  |  |  |  |  |  | } | 
| 573 |  |  |  |  |  |  | } | 
| 574 |  |  |  |  |  |  |  | 
| 575 |  |  |  |  |  |  | # Multiple emails are allowed, but we just return the first | 
| 576 | 2 | 50 |  |  |  | 9 | if (exists $session->{'e'}->[0]) { | 
| 577 | 2 |  |  |  |  | 8 | return $session->{'e'}->[0]; | 
| 578 |  |  |  |  |  |  | } | 
| 579 | 0 |  |  |  |  | 0 | return undef; | 
| 580 |  |  |  |  |  |  | } | 
| 581 |  |  |  |  |  |  |  | 
| 582 |  |  |  |  |  |  | sub session_email_arrayref { | 
| 583 | 0 |  |  | 0 | 1 | 0 | my $self=shift; | 
| 584 | 0 |  |  |  |  | 0 | my $session = $self->{'session'}; | 
| 585 |  |  |  |  |  |  |  | 
| 586 | 0 | 0 |  |  |  | 0 | if (defined $session->{'e'}) { | 
| 587 | 0 |  |  |  |  | 0 | return $session->{'e'}; | 
| 588 |  |  |  |  |  |  | } | 
| 589 | 0 |  |  |  |  | 0 | return undef; | 
| 590 |  |  |  |  |  |  | } | 
| 591 |  |  |  |  |  |  |  | 
| 592 |  |  |  |  |  |  | sub session_phone { | 
| 593 | 2 |  |  | 2 | 1 | 8 | my $self=shift; | 
| 594 | 2 |  |  |  |  | 3 | my ($p) = @_; | 
| 595 | 2 |  |  |  |  | 4 | my $session = $self->{'session'}; | 
| 596 |  |  |  |  |  |  |  | 
| 597 |  |  |  |  |  |  | # An ARRAYREF may be passed to set more than one phone number | 
| 598 | 2 | 100 |  |  |  | 7 | if (defined $p) { | 
| 599 | 1 | 50 |  |  |  | 4 | if (ref $p eq 'ARRAY') { | 
| 600 | 1 |  |  |  |  | 3 | $session->{'p'} = $p; | 
| 601 |  |  |  |  |  |  | } else { | 
| 602 | 0 |  |  |  |  | 0 | $session->{'p'} = [ $p ]; | 
| 603 |  |  |  |  |  |  | } | 
| 604 |  |  |  |  |  |  | } | 
| 605 |  |  |  |  |  |  |  | 
| 606 |  |  |  |  |  |  | # Multiple phone numbers are allowed, but we just return the first | 
| 607 | 2 | 50 |  |  |  | 8 | if (exists $session->{'p'}->[0]) { | 
| 608 | 2 |  |  |  |  | 13 | return $session->{'p'}->[0]; | 
| 609 |  |  |  |  |  |  | } | 
| 610 | 0 |  |  |  |  | 0 | return undef; | 
| 611 |  |  |  |  |  |  | } | 
| 612 |  |  |  |  |  |  |  | 
| 613 |  |  |  |  |  |  | sub session_phone_arrayref { | 
| 614 | 0 |  |  | 0 | 1 | 0 | my $self=shift; | 
| 615 | 0 |  |  |  |  | 0 | my $session = $self->{'session'}; | 
| 616 |  |  |  |  |  |  |  | 
| 617 | 0 | 0 |  |  |  | 0 | if (defined $session->{'p'}) { | 
| 618 | 0 |  |  |  |  | 0 | return $session->{'p'}; | 
| 619 |  |  |  |  |  |  | } | 
| 620 | 0 |  |  |  |  | 0 | return undef; | 
| 621 |  |  |  |  |  |  | } | 
| 622 |  |  |  |  |  |  |  | 
| 623 |  |  |  |  |  |  | sub session_key { | 
| 624 | 0 |  |  | 0 | 1 | 0 | my $self=shift; | 
| 625 | 0 |  |  |  |  | 0 | my ($method, $key) = @_; | 
| 626 |  |  |  |  |  |  |  | 
| 627 | 0 | 0 |  |  |  | 0 | $self->{'session'}->{'k'} = $method if defined $method; | 
| 628 | 0 | 0 |  |  |  | 0 | $self->{'session'}->{'k'} .= ":$key" if defined $key; | 
| 629 |  |  |  |  |  |  |  | 
| 630 | 0 |  |  |  |  | 0 | return ($self->{'session'}->{'k'} =~ /^([\w-]+):?(.*)$/); | 
| 631 |  |  |  |  |  |  | } | 
| 632 |  |  |  |  |  |  |  | 
| 633 |  |  |  |  |  |  |  | 
| 634 |  |  |  |  |  |  |  | 
| 635 |  |  |  |  |  |  | sub _attribute { | 
| 636 | 2 |  |  | 2 |  | 5 | my ($hashref, $attr_name, $attr_value) = @_; | 
| 637 | 2 | 50 |  |  |  | 7 | carp "Missing attribute name" unless (defined $attr_name); | 
| 638 |  |  |  |  |  |  |  | 
| 639 |  |  |  |  |  |  | # Set attribute to value, if value supplied | 
| 640 |  |  |  |  |  |  | # Warning - all other values are lost | 
| 641 | 2 | 100 |  |  |  | 8 | if (defined $attr_value) { | 
| 642 | 1 | 50 |  |  |  | 3 | if (ref $attr_value eq 'ARRAY') { | 
| 643 | 0 |  |  |  |  | 0 | $hashref->{'a'}->{$attr_name} = $attr_value; | 
| 644 |  |  |  |  |  |  | } else { | 
| 645 | 1 |  |  |  |  | 5 | $hashref->{'a'}->{$attr_name} = [ $attr_value ]; | 
| 646 |  |  |  |  |  |  | } | 
| 647 |  |  |  |  |  |  | } | 
| 648 |  |  |  |  |  |  |  | 
| 649 |  |  |  |  |  |  | # Return undef if attribute doesn't exist | 
| 650 | 2 | 50 |  |  |  | 23 | if (!exists $hashref->{'a'}->{$attr_name}) { | 
| 651 | 0 |  |  |  |  | 0 | return undef; | 
| 652 |  |  |  |  |  |  | } | 
| 653 |  |  |  |  |  |  |  | 
| 654 |  |  |  |  |  |  | # Return 1 if attribute exists but has no value | 
| 655 |  |  |  |  |  |  | # Return value if attribute has single value | 
| 656 |  |  |  |  |  |  | # Return arrayref if attribute has more than one value | 
| 657 | 2 |  |  |  |  | 6 | my $attrib = $hashref->{'a'}->{$attr_name}; | 
| 658 | 2 | 50 |  |  |  | 7 | if (ref $attrib eq 'ARRAY') { | 
| 659 | 2 | 50 |  |  |  | 4 | if (scalar(@{ $attrib }) == 1) { | 
|  | 2 |  |  |  |  | 7 |  | 
| 660 | 2 |  |  |  |  | 9 | return $attrib->[0]; | 
| 661 |  |  |  |  |  |  | } else { | 
| 662 | 0 |  |  |  |  | 0 | return $attrib; | 
| 663 |  |  |  |  |  |  | } | 
| 664 |  |  |  |  |  |  | } else { | 
| 665 | 0 |  |  |  |  | 0 | return ''; | 
| 666 |  |  |  |  |  |  | } | 
| 667 |  |  |  |  |  |  | } | 
| 668 |  |  |  |  |  |  |  | 
| 669 |  |  |  |  |  |  | sub session_attribute { | 
| 670 | 2 |  |  | 2 | 1 | 7 | my $self=shift; | 
| 671 |  |  |  |  |  |  |  | 
| 672 | 2 |  |  |  |  | 9 | return Net::SDP::_attribute( $self->{'session'}, @_); | 
| 673 |  |  |  |  |  |  | } | 
| 674 |  |  |  |  |  |  |  | 
| 675 |  |  |  |  |  |  | sub session_attributes { | 
| 676 | 0 |  |  | 0 | 1 | 0 | my $self=shift; | 
| 677 |  |  |  |  |  |  |  | 
| 678 | 0 |  |  |  |  | 0 | return $self->{'session'}->{'a'}; | 
| 679 |  |  |  |  |  |  | } | 
| 680 |  |  |  |  |  |  |  | 
| 681 |  |  |  |  |  |  | # Add a session atrribute | 
| 682 |  |  |  |  |  |  | sub session_add_attribute { | 
| 683 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 684 | 0 |  |  |  |  | 0 | my ($name, $value) = @_; | 
| 685 | 0 | 0 |  |  |  | 0 | carp "Missing attribute name" unless (defined $name); | 
| 686 |  |  |  |  |  |  |  | 
| 687 | 0 |  |  |  |  | 0 | my $attrib = $name; | 
| 688 | 0 | 0 |  |  |  | 0 | $attrib .= ":$value" if (defined $value); | 
| 689 | 0 |  |  |  |  | 0 | Net::SDP::_add_attribute( $self->{'session'}, 'a', $attrib ); | 
| 690 |  |  |  |  |  |  | } | 
| 691 |  |  |  |  |  |  |  | 
| 692 |  |  |  |  |  |  | # Delete a session atrribute | 
| 693 |  |  |  |  |  |  | sub session_del_attribute { | 
| 694 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 695 | 0 |  |  |  |  | 0 | my ($name) = @_; | 
| 696 | 0 | 0 |  |  |  | 0 | carp "Missing attribute name" unless (defined $name); | 
| 697 |  |  |  |  |  |  |  | 
| 698 | 0 | 0 |  |  |  | 0 | if ( exists $self->{'session'}->{'a'}->{$name} ) { | 
| 699 | 0 |  |  |  |  | 0 | delete $self->{'session'}->{'a'}->{$name}; | 
| 700 |  |  |  |  |  |  | } | 
| 701 |  |  |  |  |  |  | } | 
| 702 |  |  |  |  |  |  |  | 
| 703 |  |  |  |  |  |  |  | 
| 704 |  |  |  |  |  |  |  | 
| 705 |  |  |  |  |  |  |  | 
| 706 |  |  |  |  |  |  |  | 
| 707 |  |  |  |  |  |  | # Returns first media description of specified type | 
| 708 |  |  |  |  |  |  | sub media_desc_of_type { | 
| 709 | 1 |  |  | 1 | 1 | 177 | my $self = shift; | 
| 710 | 1 |  |  |  |  | 2 | my ($type) = @_; | 
| 711 | 1 | 50 |  |  |  | 5 | carp "Missing media type parameter" unless (defined $type); | 
| 712 |  |  |  |  |  |  |  | 
| 713 | 1 |  |  |  |  | 1 | foreach my $media ( @{$self->{'media'}} ) { | 
|  | 1 |  |  |  |  | 3 |  | 
| 714 | 1 | 50 |  |  |  | 13 | return $media if ($media->media_type() eq $type); | 
| 715 |  |  |  |  |  |  | } | 
| 716 |  |  |  |  |  |  |  | 
| 717 | 0 |  |  |  |  | 0 | return undef; | 
| 718 |  |  |  |  |  |  | } | 
| 719 |  |  |  |  |  |  |  | 
| 720 |  |  |  |  |  |  |  | 
| 721 |  |  |  |  |  |  | # Return all media descriptions | 
| 722 |  |  |  |  |  |  | sub media_desc_arrayref { | 
| 723 | 1 |  |  | 1 | 1 | 3 | my ($self) = @_; | 
| 724 |  |  |  |  |  |  |  | 
| 725 | 1 |  |  |  |  | 3 | return $self->{'media'}; | 
| 726 |  |  |  |  |  |  | } | 
| 727 |  |  |  |  |  |  |  | 
| 728 |  |  |  |  |  |  | # delete all Net::SDP::Media elements | 
| 729 |  |  |  |  |  |  | sub media_desc_delete_all { | 
| 730 | 0 |  |  | 0 | 1 | 0 | my ($self) = @_; | 
| 731 |  |  |  |  |  |  |  | 
| 732 | 0 |  |  |  |  | 0 | $self->{'media'} = [ ]; | 
| 733 |  |  |  |  |  |  |  | 
| 734 | 0 |  |  |  |  | 0 | return 0; | 
| 735 |  |  |  |  |  |  | } | 
| 736 |  |  |  |  |  |  |  | 
| 737 |  |  |  |  |  |  | # delete a specific ARRAYREF Net::SDP::Media element | 
| 738 |  |  |  |  |  |  | sub media_desc_delete { | 
| 739 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 740 | 0 |  |  |  |  | 0 | my ($num) = @_; | 
| 741 |  |  |  |  |  |  |  | 
| 742 | 0 | 0 | 0 |  |  | 0 | return 1 if ( !defined($num) || !defined($self->{'media'}->[$num]) ); | 
| 743 |  |  |  |  |  |  |  | 
| 744 | 0 |  |  |  |  | 0 | my $results = [ ]; | 
| 745 | 0 |  |  |  |  | 0 | for my $loop ( 0...(scalar(@{$self->{'media'}}) - 1) ) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 746 | 0 | 0 |  |  |  | 0 | next if ( $loop == $num ); | 
| 747 |  |  |  |  |  |  |  | 
| 748 | 0 |  |  |  |  | 0 | push @$results, $self->{'media'}->[$loop]; | 
| 749 |  |  |  |  |  |  | } | 
| 750 | 0 |  |  |  |  | 0 | $self->{'media'} = $results; | 
| 751 |  |  |  |  |  |  |  | 
| 752 | 0 |  |  |  |  | 0 | return 0; | 
| 753 |  |  |  |  |  |  | } | 
| 754 |  |  |  |  |  |  |  | 
| 755 |  |  |  |  |  |  | # Return $num time description, for backwards compatibility the | 
| 756 |  |  |  |  |  |  | # first time description by default if nothing is passed to it | 
| 757 |  |  |  |  |  |  | sub time_desc { | 
| 758 | 1 |  |  | 1 | 1 | 2 | my $self = shift; | 
| 759 | 1 |  |  |  |  | 2 | my ($num) = @_; | 
| 760 |  |  |  |  |  |  |  | 
| 761 | 1 | 50 |  |  |  | 4 | $num = 0 unless ( defined $num ); | 
| 762 | 1 | 50 |  |  |  | 22 | return undef unless ( defined($self->{'time'}->[$num]) ); | 
| 763 |  |  |  |  |  |  |  | 
| 764 |  |  |  |  |  |  | ## Ensure that one exists ? | 
| 765 | 1 |  |  |  |  | 11 | return $self->{'time'}->[$num]; | 
| 766 |  |  |  |  |  |  | } | 
| 767 |  |  |  |  |  |  |  | 
| 768 |  |  |  |  |  |  | # Return all time descriptions | 
| 769 |  |  |  |  |  |  | sub time_desc_arrayref { | 
| 770 | 0 |  |  | 0 | 1 | 0 | my ($self) = @_; | 
| 771 |  |  |  |  |  |  |  | 
| 772 | 0 |  |  |  |  | 0 | return $self->{'time'}; | 
| 773 |  |  |  |  |  |  | } | 
| 774 |  |  |  |  |  |  |  | 
| 775 |  |  |  |  |  |  | # delete all Net::SDP::Time elements | 
| 776 |  |  |  |  |  |  | sub time_desc_delete_all { | 
| 777 | 0 |  |  | 0 | 1 | 0 | my ($self) = @_; | 
| 778 |  |  |  |  |  |  |  | 
| 779 | 0 |  |  |  |  | 0 | $self->{'time'} = [ ]; | 
| 780 |  |  |  |  |  |  |  | 
| 781 | 0 |  |  |  |  | 0 | return 0; | 
| 782 |  |  |  |  |  |  | } | 
| 783 |  |  |  |  |  |  |  | 
| 784 |  |  |  |  |  |  | # delete a specific ARRAYREF Net::SDP::Time element | 
| 785 |  |  |  |  |  |  | sub time_desc_delete { | 
| 786 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 787 | 0 |  |  |  |  | 0 | my ($num) = @_; | 
| 788 |  |  |  |  |  |  |  | 
| 789 | 0 | 0 |  |  |  | 0 | return 1 unless ( defined $num ); | 
| 790 | 0 | 0 |  |  |  | 0 | return 1 unless ( defined $self->{'time'}->[$num] ); | 
| 791 |  |  |  |  |  |  |  | 
| 792 | 0 |  |  |  |  | 0 | my $results = [ ]; | 
| 793 | 0 |  |  |  |  | 0 | for my $loop ( 0...(scalar(@{$self->{'time'}}) - 1) ) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 794 | 0 | 0 |  |  |  | 0 | next if ( $loop == $num ); | 
| 795 |  |  |  |  |  |  |  | 
| 796 | 0 |  |  |  |  | 0 | push @$results, $self->{'time'}->[$loop]; | 
| 797 |  |  |  |  |  |  | } | 
| 798 | 0 |  |  |  |  | 0 | $self->{'time'} = $results; | 
| 799 |  |  |  |  |  |  |  | 
| 800 | 0 |  |  |  |  | 0 | return 0; | 
| 801 |  |  |  |  |  |  | } | 
| 802 |  |  |  |  |  |  |  | 
| 803 |  |  |  |  |  |  |  | 
| 804 |  |  |  |  |  |  | # Net::SDP::Time factory method | 
| 805 |  |  |  |  |  |  | sub new_time_desc { | 
| 806 | 2 |  |  | 2 | 1 | 249 | my $self = shift; | 
| 807 |  |  |  |  |  |  |  | 
| 808 | 2 |  |  |  |  | 17 | my $time = new Net::SDP::Time(); | 
| 809 | 2 |  |  |  |  | 12 | push( @{$self->{'time'}}, $time ); | 
|  | 2 |  |  |  |  | 7 |  | 
| 810 |  |  |  |  |  |  |  | 
| 811 | 2 |  |  |  |  | 7 | return $time; | 
| 812 |  |  |  |  |  |  | } | 
| 813 |  |  |  |  |  |  |  | 
| 814 |  |  |  |  |  |  |  | 
| 815 |  |  |  |  |  |  | # Net::SDP::Media factory method | 
| 816 |  |  |  |  |  |  | sub new_media_desc { | 
| 817 | 1 |  |  | 1 | 1 | 6 | my $self = shift; | 
| 818 | 1 |  |  |  |  | 2 | my ($media_type) = @_; | 
| 819 |  |  |  |  |  |  |  | 
| 820 | 1 |  |  |  |  | 8 | my $media = new Net::SDP::Media(); | 
| 821 | 1 | 50 |  |  |  | 8 | $media->media_type( $media_type ) if (defined $media_type); | 
| 822 | 1 |  |  |  |  | 1 | push( @{$self->{'media'}}, $media ); | 
|  | 1 |  |  |  |  | 3 |  | 
| 823 |  |  |  |  |  |  |  | 
| 824 | 1 |  |  |  |  | 3 | return $media; | 
| 825 |  |  |  |  |  |  | } | 
| 826 |  |  |  |  |  |  |  | 
| 827 |  |  |  |  |  |  |  | 
| 828 |  |  |  |  |  |  |  | 
| 829 |  |  |  |  |  |  | sub DESTROY { | 
| 830 | 4 |  |  | 4 |  | 4072 | my $self=shift; | 
| 831 |  |  |  |  |  |  |  | 
| 832 |  |  |  |  |  |  | } | 
| 833 |  |  |  |  |  |  |  | 
| 834 |  |  |  |  |  |  |  | 
| 835 |  |  |  |  |  |  | 1; | 
| 836 |  |  |  |  |  |  |  | 
| 837 |  |  |  |  |  |  | __END__ |