3 # Copyright (c) 1995-1997 Graham Barr <gbarr@pobox.com>. All rights reserved.
4 # This program is free software; you can redistribute it and/or
5 # modify it under the same terms as Perl itself.
10 use vars qw(@ISA $VERSION $debug);
18 @ISA = qw(Net::Cmd IO::Socket::INET);
23 my $type = ref($self) || $self;
30 $host=delete $arg{Host};
34 $host ||= $ENV{NNTPSERVER} || $ENV{NEWSHOST};
36 my $hosts = defined $host ? [ $host ] : $NetConfig{nntp_hosts};
42 foreach $h (@{$hosts})
44 $obj = $type->SUPER::new(PeerAddr => ($host = $h),
45 PeerPort => $arg{Port} || 'nntp(119)',
47 Timeout => defined $arg{Timeout}
56 ${*$obj}{'net_nntp_host'} = $host;
59 $obj->debug(exists $arg{Debug} ? $arg{Debug} : undef);
61 unless ($obj->response() == CMD_OK)
68 my @m = $obj->message;
70 unless(exists $arg{Reader} && $arg{Reader} == 0) {
71 # if server is INN and we have transfer rights the we are currently
72 # talking to innd not nnrpd
75 # If reader suceeds the we need to consider this code to determine postok
80 # I want to ignore this failure, so restore the previous status.
81 $obj->set_status($c,\@m);
85 ${*$obj}{'net_nntp_post'} = $c == 200 ? 1 : 0;
92 ${*$me}{'net_nntp_host'};
101 if((ref($nntp) and $nntp->code == 350 and $text =~ /^(\S+)/)
102 || ($text =~ /^(authinfo\s+pass)/io))
112 @_ == 1 or croak 'usage: $nntp->postok()';
114 ${*$nntp}{'net_nntp_post'} || 0;
119 @_ >= 1 && @_ <= 3 or croak 'usage: $nntp->article( [ MSGID ], [ FH ] )';
123 @fh = (pop) if @_ == 2 || (@_ && (ref($_[0]) || ref(\$_[0]) eq 'GLOB'));
126 ? $nntp->read_until_dot(@fh)
131 @_ >= 1 && @_ <= 2 or croak 'usage: $nntp->articlefh( [ MSGID ] )';
134 return unless $nntp->_ARTICLE(@_);
135 return $nntp->tied_fh;
140 @_ == 3 or croak 'usage: $nntp->authinfo( USER, PASS )';
141 my($nntp,$user,$pass) = @_;
143 $nntp->_AUTHINFO("USER",$user) == CMD_MORE
144 && $nntp->_AUTHINFO("PASS",$pass) == CMD_OK;
149 @_ == 3 or croak 'usage: $nntp->authinfo( USER, PASS )';
150 my($nntp,$user,$pass) = @_;
152 $nntp->_AUTHINFO('SIMPLE') == CMD_MORE
153 && $nntp->command($user,$pass)->response == CMD_OK;
158 @_ >= 1 && @_ <= 3 or croak 'usage: $nntp->body( [ MSGID ], [ FH ] )';
162 @fh = (pop) if @_ == 2 || (@_ && ref($_[0]) || ref(\$_[0]) eq 'GLOB');
165 ? $nntp->read_until_dot(@fh)
171 @_ >= 1 && @_ <= 2 or croak 'usage: $nntp->bodyfh( [ MSGID ] )';
173 return unless $nntp->_BODY(@_);
174 return $nntp->tied_fh;
179 @_ >= 1 && @_ <= 3 or croak 'usage: $nntp->head( [ MSGID ], [ FH ] )';
183 @fh = (pop) if @_ == 2 || (@_ && ref($_[0]) || ref(\$_[0]) eq 'GLOB');
186 ? $nntp->read_until_dot(@fh)
192 @_ >= 1 && @_ <= 2 or croak 'usage: $nntp->headfh( [ MSGID ] )';
194 return unless $nntp->_HEAD(@_);
195 return $nntp->tied_fh;
200 @_ == 1 || @_ == 2 or croak 'usage: $nntp->nntpstat( [ MSGID ] )';
203 $nntp->_STAT(@_) && $nntp->message =~ /(<[^>]+>)/o
211 @_ == 1 || @_ == 2 or croak 'usage: $nntp->group( [ GROUP ] )';
213 my $grp = ${*$nntp}{'net_nntp_group'} || undef;
216 unless(@_ || wantarray);
220 return wantarray ? () : undef
221 unless $nntp->_GROUP($newgrp || $grp || "")
222 && $nntp->message =~ /(\d+)\s+(\d+)\s+(\d+)\s+(\S+)/;
224 my($count,$first,$last,$group) = ($1,$2,$3,$4);
226 # group may be replied as '(current group)'
227 $group = ${*$nntp}{'net_nntp_group'}
230 ${*$nntp}{'net_nntp_group'} = $group;
233 ? ($count,$first,$last,$group)
239 @_ == 1 or croak 'usage: $nntp->help()';
243 ? $nntp->read_until_dot
249 @_ >= 2 or croak 'usage: $nntp->ihave( MESSAGE-ID [, MESSAGE ])';
253 $nntp->_IHAVE($mid) && $nntp->datasend(@_)
254 ? @_ == 0 || $nntp->dataend
260 @_ == 1 or croak 'usage: $nntp->last()';
263 $nntp->_LAST && $nntp->message =~ /(<[^>]+>)/o
270 @_ == 1 or croak 'usage: $nntp->list()';
280 @_ >= 2 or croak 'usage: $nntp->newgroups( SINCE [, DISTRIBUTIONS ])';
282 my $time = _timestr(shift);
283 my $dist = shift || "";
285 $dist = join(",", @{$dist})
288 $nntp->_NEWGROUPS($time,$dist)
295 @_ >= 2 && @_ <= 4 or
296 croak 'usage: $nntp->newnews( SINCE [, GROUPS [, DISTRIBUTIONS ]])';
298 my $time = _timestr(shift);
299 my $grp = @_ ? shift : $nntp->group;
300 my $dist = shift || "";
303 $grp = join(",", @{$grp})
306 $dist = join(",", @{$dist})
309 $nntp->_NEWNEWS($grp,$time,$dist)
310 ? $nntp->_articlelist
316 @_ == 1 or croak 'usage: $nntp->next()';
319 $nntp->_NEXT && $nntp->message =~ /(<[^>]+>)/o
326 @_ >= 1 or croak 'usage: $nntp->post( [ MESSAGE ] )';
329 $nntp->_POST() && $nntp->datasend(@_)
330 ? @_ == 0 || $nntp->dataend
336 return unless $nntp->_POST();
337 return $nntp->tied_fh;
342 @_ == 1 or croak 'usage: $nntp->quit()';
351 @_ == 1 or croak 'usage: $nntp->slave()';
358 ## The following methods are not implemented by all servers
363 @_ == 1 || @_ == 2 or croak 'usage: $nntp->active( [ PATTERN ] )';
366 $nntp->_LIST('ACTIVE',@_)
373 @_ == 1 or croak 'usage: $nntp->active_times()';
376 $nntp->_LIST('ACTIVE.TIMES')
383 @_ == 1 or croak 'usage: $nntp->distributions()';
386 $nntp->_LIST('DISTRIBUTIONS')
387 ? $nntp->_description
391 sub distribution_patterns
393 @_ == 1 or croak 'usage: $nntp->distributions()';
399 $nntp->_LIST('DISTRIB.PATS') && ($arr = $nntp->read_until_dot)
400 ? [grep { /^\d/ && (chomp, $_ = [ split /:/ ]) } @$arr]
406 @_ == 1 || @_ == 2 or croak 'usage: $nntp->newsgroups( [ PATTERN ] )';
409 $nntp->_LIST('NEWSGROUPS',@_)
410 ? $nntp->_description
416 @_ == 1 or croak 'usage: $nntp->overview_fmt()';
419 $nntp->_LIST('OVERVIEW.FMT')
420 ? $nntp->_articlelist
426 @_ == 1 or croak 'usage: $nntp->subscriptions()';
429 $nntp->_LIST('SUBSCRIPTIONS')
430 ? $nntp->_articlelist
436 @_ == 1 || @_ == 2 or croak 'usage: $nntp->listgroup( [ GROUP ] )';
439 $nntp->_LISTGROUP(@_)
440 ? $nntp->_articlelist
446 @_ == 1 or croak 'usage: $nntp->reader()';
449 $nntp->_MODE('READER');
454 @_ == 1 || @_ == 2 or croak 'usage: $nntp->xgtitle( [ PATTERN ] )';
458 ? $nntp->_description
464 @_ >= 2 && @_ <= 4 or croak 'usage: $nntp->xhdr( HEADER, [ MESSAGE-SPEC ] )';
467 my $arg = _msg_arg(@_);
469 $nntp->_XHDR($hdr, $arg)
470 ? $nntp->_description
476 @_ == 2 || @_ == 3 or croak 'usage: $nntp->xover( MESSAGE-SPEC )';
478 my $arg = _msg_arg(@_);
487 @_ == 4 || @_ == 5 or croak '$nntp->xpat( HEADER, PATTERN, MESSAGE-SPEC )';
491 my $arg = _msg_arg(@_);
493 $pat = join(" ", @$pat)
496 $nntp->_XPAT($hdr,$arg,$pat)
497 ? $nntp->_description
503 @_ == 2 or croak 'usage: $nntp->xpath( MESSAGE-ID )';
507 unless $nntp->_XPATH($mid);
509 my $m; ($m = $nntp->message) =~ s/^\d+\s+//o;
510 my @p = split /\s+/, $m;
512 wantarray ? @p : $p[0];
517 @_ == 2 || @_ == 3 or croak 'usage: $nntp->xrover( MESSAGE-SPEC )';
519 my $arg = _msg_arg(@_);
522 ? $nntp->_description
528 @_ == 1 or croak 'usage: $nntp->date()';
531 $nntp->_DATE && $nntp->message =~ /(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/
532 ? timegm($6,$5,$4,$3,$2-1,$1 - 1900)
538 ## Private subroutines
548 carp "Depriciated passing of two message numbers, "
551 $spec = [ $spec, $_[0] ];
559 if(defined $spec->[1])
562 if $spec->[1] != $spec->[0];
564 if $spec->[1] > $spec->[0];
579 my @g = reverse((gmtime($time))[0..5]);
582 sprintf "%02d%02d%02d %02d%02d%02d GMT", @g;
588 my $arr = $nntp->read_until_dot or
596 my @a = split(/[\s\n]+/,$ln);
597 $hash->{$a[0]} = [ @a[1,2,3] ];
606 my $arr = $nntp->read_until_dot or
614 my @a = split(/[\t\n]/,$ln);
616 $hash->{$m} = [ @a ];
625 my $arr = $nntp->read_until_dot;
636 my $arr = $nntp->read_until_dot or
647 if $ln =~ s/^\s*(\S+)\s*//o;
658 sub _ARTICLE { shift->command('ARTICLE',@_)->response == CMD_OK }
659 sub _AUTHINFO { shift->command('AUTHINFO',@_)->response }
660 sub _BODY { shift->command('BODY',@_)->response == CMD_OK }
661 sub _DATE { shift->command('DATE')->response == CMD_INFO }
662 sub _GROUP { shift->command('GROUP',@_)->response == CMD_OK }
663 sub _HEAD { shift->command('HEAD',@_)->response == CMD_OK }
664 sub _HELP { shift->command('HELP',@_)->response == CMD_INFO }
665 sub _IHAVE { shift->command('IHAVE',@_)->response == CMD_MORE }
666 sub _LAST { shift->command('LAST')->response == CMD_OK }
667 sub _LIST { shift->command('LIST',@_)->response == CMD_OK }
668 sub _LISTGROUP { shift->command('LISTGROUP',@_)->response == CMD_OK }
669 sub _NEWGROUPS { shift->command('NEWGROUPS',@_)->response == CMD_OK }
670 sub _NEWNEWS { shift->command('NEWNEWS',@_)->response == CMD_OK }
671 sub _NEXT { shift->command('NEXT')->response == CMD_OK }
672 sub _POST { shift->command('POST',@_)->response == CMD_MORE }
673 sub _QUIT { shift->command('QUIT',@_)->response == CMD_OK }
674 sub _SLAVE { shift->command('SLAVE',@_)->response == CMD_OK }
675 sub _STAT { shift->command('STAT',@_)->response == CMD_OK }
676 sub _MODE { shift->command('MODE',@_)->response == CMD_OK }
677 sub _XGTITLE { shift->command('XGTITLE',@_)->response == CMD_OK }
678 sub _XHDR { shift->command('XHDR',@_)->response == CMD_OK }
679 sub _XPAT { shift->command('XPAT',@_)->response == CMD_OK }
680 sub _XPATH { shift->command('XPATH',@_)->response == CMD_OK }
681 sub _XOVER { shift->command('XOVER',@_)->response == CMD_OK }
682 sub _XROVER { shift->command('XROVER',@_)->response == CMD_OK }
683 sub _XTHREAD { shift->unsupported }
684 sub _XSEARCH { shift->unsupported }
685 sub _XINDEX { shift->unsupported }
694 defined(fileno($nntp)) && $nntp->quit
704 Net::NNTP - NNTP Client class
710 $nntp = Net::NNTP->new("some.host.name");
715 C<Net::NNTP> is a class implementing a simple NNTP client in Perl as described
716 in RFC977. C<Net::NNTP> inherits its communication methods from C<Net::Cmd>
722 =item new ( [ HOST ] [, OPTIONS ])
724 This is the constructor for a new Net::NNTP object. C<HOST> is the
725 name of the remote host to which a NNTP connection is required. If not
726 given then it may be passed as the C<Host> option described below. If no host is passed
727 then two environment variables are checked, first C<NNTPSERVER> then
728 C<NEWSHOST>, then C<Net::Config> is checked, and if a host is not found
729 then C<news> is used.
731 C<OPTIONS> are passed in a hash like fashion, using key and value pairs.
732 Possible options are:
734 B<Host> - NNTP host to connect to. It may be a single scalar, as defined for
735 the C<PeerAddr> option in L<IO::Socket::INET>, or a reference to
736 an array with hosts to try in turn. The L</host> method will return the value
737 which was used to connect to the host.
739 B<Timeout> - Maximum time, in seconds, to wait for a response from the
740 NNTP server, a value of zero will cause all IO operations to block.
743 B<Debug> - Enable the printing of debugging information to STDERR
745 B<Reader> - If the remote server is INN then initially the connection
746 will be to nnrpd, by default C<Net::NNTP> will issue a C<MODE READER> command
747 so that the remote server becomes innd. If the C<Reader> option is given
748 with a value of zero, then this command will not be sent and the
749 connection will be left talking to nnrpd.
755 Unless otherwise stated all methods return either a I<true> or I<false>
756 value, with I<true> meaning that the operation was a success. When a method
757 states that it returns a value, failure will be returned as I<undef> or an
762 =item article ( [ MSGID|MSGNUM ], [FH] )
764 Retrieve the header, a blank line, then the body (text) of the
767 If C<FH> is specified then it is expected to be a valid filehandle
768 and the result will be printed to it, on success a true value will be
769 returned. If C<FH> is not specified then the return value, on success,
770 will be a reference to an array containing the article requested, each
771 entry in the array will contain one line of the article.
773 If no arguments are passed then the current article in the currently
774 selected newsgroup is fetched.
776 C<MSGNUM> is a numeric id of an article in the current newsgroup, and
777 will change the current article pointer. C<MSGID> is the message id of
778 an article as shown in that article's header. It is anticipated that the
779 client will obtain the C<MSGID> from a list provided by the C<newnews>
780 command, from references contained within another article, or from the
781 message-id provided in the response to some other commands.
783 If there is an error then C<undef> will be returned.
785 =item body ( [ MSGID|MSGNUM ], [FH] )
787 Like C<article> but only fetches the body of the article.
789 =item head ( [ MSGID|MSGNUM ], [FH] )
791 Like C<article> but only fetches the headers for the article.
793 =item articlefh ( [ MSGID|MSGNUM ] )
795 =item bodyfh ( [ MSGID|MSGNUM ] )
797 =item headfh ( [ MSGID|MSGNUM ] )
799 These are similar to article(), body() and head(), but rather than
800 returning the requested data directly, they return a tied filehandle
801 from which to read the article.
803 =item nntpstat ( [ MSGID|MSGNUM ] )
805 The C<nntpstat> command is similar to the C<article> command except that no
806 text is returned. When selecting by message number within a group,
807 the C<nntpstat> command serves to set the "current article pointer" without
810 Using the C<nntpstat> command to
811 select by message-id is valid but of questionable value, since a
812 selection by message-id does B<not> alter the "current article pointer".
814 Returns the message-id of the "current article".
816 =item group ( [ GROUP ] )
818 Set and/or get the current group. If C<GROUP> is not given then information
819 is returned on the current group.
821 In a scalar context it returns the group name.
823 In an array context the return value is a list containing, the number
824 of articles in the group, the number of the first article, the number
825 of the last article and the group name.
827 =item ihave ( MSGID [, MESSAGE ])
829 The C<ihave> command informs the server that the client has an article
830 whose id is C<MSGID>. If the server desires a copy of that
831 article, and C<MESSAGE> has been given the it will be sent.
833 Returns I<true> if the server desires the article and C<MESSAGE> was
834 successfully sent,if specified.
836 If C<MESSAGE> is not specified then the message must be sent using the
837 C<datasend> and C<dataend> methods from L<Net::Cmd>
839 C<MESSAGE> can be either an array of lines or a reference to an array.
843 Set the "current article pointer" to the previous article in the current
846 Returns the message-id of the article.
850 Returns the date on the remote server. This date will be in a UNIX time
851 format (seconds since 1970)
855 C<postok> will return I<true> if the servers initial response indicated
856 that it will allow posting.
858 =item authinfo ( USER, PASS )
860 Authenticates to the server (using AUTHINFO USER / AUTHINFO PASS)
861 using the supplied username and password. Please note that the
862 password is sent in clear text to the server. This command should not
863 be used with valuable passwords unless the connection to the server is
868 Obtain information about all the active newsgroups. The results is a reference
869 to a hash where the key is a group name and each value is a reference to an
870 array. The elements in this array are:- the last article number in the group,
871 the first article number in the group and any information flags about the group.
873 =item newgroups ( SINCE [, DISTRIBUTIONS ])
875 C<SINCE> is a time value and C<DISTRIBUTIONS> is either a distribution
876 pattern or a reference to a list of distribution patterns.
877 The result is the same as C<list>, but the
878 groups return will be limited to those created after C<SINCE> and, if
879 specified, in one of the distribution areas in C<DISTRIBUTIONS>.
881 =item newnews ( SINCE [, GROUPS [, DISTRIBUTIONS ]])
883 C<SINCE> is a time value. C<GROUPS> is either a group pattern or a reference
884 to a list of group patterns. C<DISTRIBUTIONS> is either a distribution
885 pattern or a reference to a list of distribution patterns.
887 Returns a reference to a list which contains the message-ids of all news posted
888 after C<SINCE>, that are in a groups which matched C<GROUPS> and a
889 distribution which matches C<DISTRIBUTIONS>.
893 Set the "current article pointer" to the next article in the current
896 Returns the message-id of the article.
898 =item post ( [ MESSAGE ] )
900 Post a new article to the news server. If C<MESSAGE> is specified and posting
901 is allowed then the message will be sent.
903 If C<MESSAGE> is not specified then the message must be sent using the
904 C<datasend> and C<dataend> methods from L<Net::Cmd>
906 C<MESSAGE> can be either an array of lines or a reference to an array.
908 The message, either sent via C<datasend> or as the C<MESSAGE>
909 parameter, must be in the format as described by RFC822 and must
910 contain From:, Newsgroups: and Subject: headers.
914 Post a new article to the news server using a tied filehandle. If
915 posting is allowed, this method will return a tied filehandle that you
916 can print() the contents of the article to be posted. You must
917 explicitly close() the filehandle when you are finished posting the
918 article, and the return value from the close() call will indicate
919 whether the message was successfully posted.
923 Tell the remote server that I am not a user client, but probably another
928 Quit the remote server and close the socket connection.
932 =head2 Extension methods
934 These methods use commands that are not part of the RFC977 documentation. Some
935 servers may not support all of them.
939 =item newsgroups ( [ PATTERN ] )
941 Returns a reference to a hash where the keys are all the group names which
942 match C<PATTERN>, or all of the groups if no pattern is specified, and
943 each value contains the description text for the group.
945 =item distributions ()
947 Returns a reference to a hash where the keys are all the possible
948 distribution names and the values are the distribution descriptions.
950 =item subscriptions ()
952 Returns a reference to a list which contains a list of groups which
953 are recommended for a new user to subscribe to.
955 =item overview_fmt ()
957 Returns a reference to an array which contain the names of the fields returned
960 =item active_times ()
962 Returns a reference to a hash where the keys are the group names and each
963 value is a reference to an array containing the time the groups was created
964 and an identifier, possibly an Email address, of the creator.
966 =item active ( [ PATTERN ] )
968 Similar to C<list> but only active groups that match the pattern are returned.
969 C<PATTERN> can be a group pattern.
971 =item xgtitle ( PATTERN )
973 Returns a reference to a hash where the keys are all the group names which
974 match C<PATTERN> and each value is the description text for the group.
976 =item xhdr ( HEADER, MESSAGE-SPEC )
978 Obtain the header field C<HEADER> for all the messages specified.
980 The return value will be a reference
981 to a hash where the keys are the message numbers and each value contains
982 the text of the requested header for that message.
984 =item xover ( MESSAGE-SPEC )
986 The return value will be a reference
987 to a hash where the keys are the message numbers and each value contains
988 a reference to an array which contains the overview fields for that
991 The names of the fields can be obtained by calling C<overview_fmt>.
993 =item xpath ( MESSAGE-ID )
995 Returns the path name to the file on the server which contains the specified
998 =item xpat ( HEADER, PATTERN, MESSAGE-SPEC)
1000 The result is the same as C<xhdr> except the is will be restricted to
1001 headers where the text of the header matches C<PATTERN>
1005 The XROVER command returns reference information for the article(s)
1008 Returns a reference to a HASH where the keys are the message numbers and the
1009 values are the References: lines from the articles
1011 =item listgroup ( [ GROUP ] )
1013 Returns a reference to a list of all the active messages in C<GROUP>, or
1014 the current group if C<GROUP> is not specified.
1018 Tell the server that you are a reader and not another server.
1020 This is required by some servers. For example if you are connecting to
1021 an INN server and you have transfer permission your connection will
1022 be connected to the transfer daemon, not the NNTP daemon. Issuing
1023 this command will cause the transfer daemon to hand over control
1026 Some servers do not understand this command, but issuing it and ignoring
1027 the response is harmless.
1033 The following NNTP command are unsupported by the package, and there are
1047 C<MESSAGE-SPEC> is either a single message-id, a single message number, or
1048 a reference to a list of two message numbers.
1050 If C<MESSAGE-SPEC> is a reference to a list of two message numbers and the
1051 second number in a range is less than or equal to the first then the range
1052 represents all messages in the group after the first message number.
1054 B<NOTE> For compatibility reasons only with earlier versions of Net::NNTP
1055 a message spec can be passed as a list of two numbers, this is deprecated
1056 and a reference to the list should now be passed
1060 The C<NNTP> protocol uses the C<WILDMAT> format for patterns.
1061 The WILDMAT format was first developed by Rich Salz based on
1062 the format used in the UNIX "find" command to articulate
1063 file names. It was developed to provide a uniform mechanism
1064 for matching patterns in the same manner that the UNIX shell
1067 Patterns are implicitly anchored at the
1068 beginning and end of each string when testing for a match.
1070 There are five pattern matching operations other than a strict
1071 one-to-one match between the pattern and the source to be
1072 checked for a match.
1074 The first is an asterisk C<*> to match any sequence of zero or more
1077 The second is a question mark C<?> to match any single character. The
1078 third specifies a specific set of characters.
1080 The set is specified as a list of characters, or as a range of characters
1081 where the beginning and end of the range are separated by a minus (or dash)
1082 character, or as any combination of lists and ranges. The dash can
1083 also be included in the set as a character it if is the beginning
1084 or end of the set. This set is enclosed in square brackets. The
1085 close square bracket C<]> may be used in a set if it is the first
1086 character in the set.
1088 The fourth operation is the same as the
1089 logical not of the third operation and is specified the same
1090 way as the third with the addition of a caret character C<^> at
1091 the beginning of the test string just inside the open square
1094 The final operation uses the backslash character to
1095 invalidate the special meaning of an open square bracket C<[>,
1096 the asterisk, backslash or the question mark. Two backslashes in
1097 sequence will result in the evaluation of the backslash as a
1098 character with no special meaning.
1106 matches any single character other than a close square
1107 bracket or a minus sign/dash.
1111 matches any string that ends with the string "bdc"
1112 including the string "bdc" (without quotes).
1114 =item C<[0-9a-zA-Z]>
1116 matches any single printable alphanumeric ASCII character.
1120 matches any four character string which begins
1121 with a and ends with d.
1133 Graham Barr <gbarr@pobox.com>
1137 Copyright (c) 1995-1997 Graham Barr. All rights reserved.
1138 This program is free software; you can redistribute it and/or modify
1139 it under the same terms as Perl itself.
1143 I<$Id: //depot/libnet/Net/NNTP.pm#18 $>