]> git.donarmstrong.com Git - infobot.git/blob - src/Modules/Dict.pl
standard TODO: and FIXME:
[infobot.git] / src / Modules / Dict.pl
1 #
2 #  Dict.pl: Frontend to dict.org.
3 #   Author: dms
4 #  Version: v0.6c (20000924).
5 #  Created: 19990914.
6 #
7 # see http://luetzschena-stahmeln.de/dictd/
8 # for a list of dict servers
9
10 package Dict;
11
12 use IO::Socket;
13 use strict;
14
15 #use vars qw(PF_INET);
16
17 # need a specific host||ip.
18 #my $server     = "dict.org";
19 my $server      = "127.0.0.1";
20
21 sub Dict {
22     my ($query) = @_;
23 #    return unless &::loadPerlModule("IO::Socket");
24     my $port    = 2628;
25     my $proto   = getprotobyname('tcp');
26     my @results;
27     my $retval;
28
29     for ($query) {
30         s/^[\s\t]+//;
31         s/[\s\t]+$//;
32         s/[\s\t]+/ /;
33     }
34
35     # connect.
36     # TODO: make strict-safe constants... so we can defer IO::Socket load.
37     my $socket  = new IO::Socket;
38     socket($socket, PF_INET, SOCK_STREAM, $proto) or return "error: socket: $!";
39     eval {
40         local $SIG{ALRM} = sub { die "alarm" };
41         alarm 10;
42         connect($socket, sockaddr_in($port, inet_aton($server))) or die "error: connect: $!";
43         alarm 0;
44     };
45
46     if ($@) {
47         # failure.
48         $retval = "i could not get info from $server '$@'";
49     } else {                            # success.
50         $socket->autoflush(1);  # required.
51
52         my $num;
53         if ($query =~ s/^(\d+)\s+//) {
54             $num = $1;
55         }
56
57         # body.
58         push(@results, &Dict_Wordnet($socket,$query));
59         push(@results, &Dict_Foldoc($socket,$query));
60         # end.
61
62         print $socket "QUIT\n";
63         close $socket;
64
65         my $total = scalar @results;
66
67         if ($total == 0) {
68             $num = undef;
69         }
70
71         if (defined $num and ($num > $total or $num < 1)) {
72             &::msg($::who, "error: choice in definition is out of range.");
73             return;
74         }
75
76         # parse the results.
77         if ($total > 1) {
78             if (defined $num) {
79                 $retval = sprintf("[%d/%d] %s", $num, $total, $results[$num-1]);
80             } else {
81                 # suggested by larne and others.
82                 my $prefix = "Dictionary '$query' ";
83                 $retval = &::formListReply(1, $prefix, @results);
84             }
85         } elsif ($total == 1) {
86             $retval = "Dictionary '$query' ".$results[0];
87         } else {
88             $retval = "could not find definition for \002$query\002";
89         }
90     }
91
92     &::performStrictReply($retval);
93 }
94
95 sub Dict_Wordnet {
96     my ($socket, $query) = @_;
97     my @results;
98
99     &::status("Dict: asking Wordnet.");
100     print $socket "DEFINE wn \"$query\"\n";
101
102     my $def             = "";
103     my $wordtype        = "";
104
105     while (<$socket>) {
106         chop;   # remove \n
107         chop;   # remove \r
108
109         &::DEBUG("got '$_'");
110         if ($_ eq ".") {                                # end of def.
111             push(@results, $def);
112         } elsif (/^250 /) {                             # stats.
113             last;
114         } elsif (/^552 no match/) {                     # no match.
115             return;
116         } elsif (/^\s+(\S+ )?(\d+)?: (.*)/) {   # start of sub def.
117             my $text = $3;
118             $def =~ s/\s+$//;
119 ###         &::DEBUG("def => '$def'.");
120             push(@results, $def)                if ($def ne "");
121             $def = $text;
122
123             if (0) {    # old non-fLR format.
124                 $def = "$query $wordtype: $text" if (defined $text);
125                 $wordtype = substr($1,0,-1)     if (defined $1);
126 ###             &::DEBUG("_ => '$_'.") if (!defined $text);
127             }
128
129         } elsif (/^\s+(.*)/) {
130             s/^\s{2,}/ /;
131             $def        .= $_;
132             $def =~ s/\[.*?\]$//g;
133         }
134     }
135
136     &::status("Dict: wordnet: found ". scalar(@results) ." defs.");
137
138     return if (!scalar @results);
139
140     return @results;
141 }
142
143 sub Dict_Foldoc {
144     my ($socket,$query) = @_;
145     my @results;
146
147     &::status("Dict: asking Foldoc.");
148     print $socket "DEFINE foldoc \"$query\"\n";
149
150     my $firsttime = 1;
151     my $string;
152     while (<$socket>) {
153         chop;   # remove \n
154         chop;   # remove \r
155
156         &::DEBUG("got '$_'");
157         return if /^552 /;              # no match.
158
159         if ($firsttime) {
160             $firsttime-- if ($_ eq "");
161             next;
162         }
163
164         last if (/^250/ or /^\.$/);     # stats; end of def.
165
166         s/^\s+|\s+$//g;                 # each line.
167
168         if ($_ eq "") {                 # sub def separator.
169             $string =~ s/^\s+|\s+$//g;  # sub def.
170             $string =~ s/[{}]//g;
171
172             next if ($string eq "");
173
174             push(@results, $string);
175             $string = "";
176         }
177
178         $string .= $_." ";
179     }
180
181     &::status("Dict: foldoc: found ". scalar(@results) ." defs.");
182
183     return if (!scalar @results);
184     pop @results;       # last def is date of entry.
185
186     return @results;
187 }
188
189 1;