ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/Net-IRC3/samples/jsonclient
Revision: 1.6
Committed: Sun Jan 14 01:10:52 2007 UTC (19 years, 8 months ago) by elmex
Branch: MAIN
Changes since 1.5: +114 -21 lines
Log Message:
further improvements of the jsonchat framework. maybe in some weeks i
have a new irc client for me!

File Contents

# User Rev Content
1 elmex 1.1 #!/usr/bin/perl
2     use strict;
3 elmex 1.5 use utf8;
4 elmex 1.6 use URI;
5 elmex 1.1 use JSONConnection;
6 elmex 1.3 use JSON::Syck;
7 elmex 1.2 use POSIX qw(strftime);
8     use CursesChatMainwindow;
9 elmex 1.1
10 elmex 1.6 our @highlight;
11 elmex 1.3 our $CFG;
12 elmex 1.4 our %known_ids;
13 elmex 1.6 our %rev_known_ids;
14 elmex 1.4 our $js;
15     our %completion = map { $_ => 1 } qw{
16 elmex 1.6 /buffer
17     /colors
18     /list_buffers
19     /reload /remote_reload /reconnect
20 elmex 1.4 };
21    
22     my $d = 0;
23     my $wt;
24     sub timer {
25     $wt = AnyEvent->timer (after => 3, cb => sub {
26     printline (status => [0, "TEST $d"]); $d++;
27     timer ();
28     });
29     }
30    
31 elmex 1.6 sub search_buffer {
32     my ($id) = @_;
33    
34     for (keys %{$::CFG->{buffers}}) {
35     if ($::CFG->{buffers}->{$_} eq $id) {
36     return $_;
37     }
38     }
39    
40     return undef
41     }
42    
43 elmex 1.4 sub write_chatline {
44 elmex 1.6 my ($buffer, $nick, $time, $msg, $mode) = @_;
45     my $nick_color = $mode eq 'local' ? 7 : ($mode eq 'private' ? 4 : 0);
46     my $ts = '[' . POSIX::strftime ("%T", localtime ($time)) . ']';
47     my (@chatline) = (("p".length $ts), 0, $ts, 0, " <", $nick_color, "$nick", 0, "> ", 0, $msg);
48 elmex 1.4 printline ($buffer, \@chatline);
49     }
50 elmex 1.3
51     sub load_cfg {
52     $CFG ||= {};
53     return unless -e "$ENV{HOME}/.jsonircclrc";
54     open CFGH, "<", "$ENV{HOME}/.jsonircclrc" or die "Couldn't open ~/.jsonircclrc: $!";
55     $::CFG = JSON::Syck::Load (do { local $/; <CFGH> });
56     }
57    
58 elmex 1.6 sub maybe_pop_highlight {
59     my ($buffer) = @_;
60     @highlight = grep { $buffer ne $_->[0] } @highlight;
61     printline (msgline => [map { (103, $_->[1] || $_->[0], 0, ' ') } @highlight]);
62     }
63    
64     sub push_highlight {
65     my ($id) = @_;
66    
67     unless (grep { $_->[0] eq $id } (@highlight, [current_buffer ()])) {
68     push @highlight, [$id, search_buffer ($id)];
69     printline (msgline => [map { (103, $_->[1] || $_->[0], 0, ' ') } @highlight]);
70     }
71     }
72    
73     sub change_buffer {
74     my ($new_buf) = @_;
75     maybe_pop_highlight ($new_buf);
76     select_buffer ($new_buf);
77     }
78    
79     sub prettyfy_id {
80     my ($id) = @_;
81     my $uri = URI->new ($id);
82     my $a = $uri->authority;
83     my $p = ($uri->path_segments ())[1];
84     $rev_known_ids{"$a/$p"} = $id;
85     "$a/$p"
86     }
87    
88 elmex 1.3 load_cfg ();
89    
90 elmex 1.2 my $c = AnyEvent->condvar;
91 elmex 1.1
92 elmex 1.2 #timer ();
93 elmex 1.1
94     $js =
95 elmex 1.6 JSONClientConnection->new (
96     packet_cb => sub {
97     my ($js, $data) = @_;
98     require JSON::Syck;
99    
100     if ($data->{type} eq 'message') {
101     my ($src_id) = ($data->{src});
102     my $pretty_id = prettyfy_id ($src_id);
103     $known_ids{$src_id}->{send_id} = $data->{to}->{id};
104    
105     if ($data->{msg_type} eq 'private') {
106     push_highlight ($pretty_id);
107     } else {
108     for (@{$::CFG->{highlight}}) {
109     if ($data->{message} =~ m/$_/) {
110     push_highlight ($pretty_id);
111     }
112     }
113     }
114    
115     write_chatline ($pretty_id, prettyfy_id ($data->{from}->{id}), $data->{timestamp}, $data->{message}, $data->{msg_type});
116     } elsif ($data->{type} eq 'info') {
117     printline (status => [3, 'INFO: ' . $data->{message}]);
118     } elsif ($data->{type} eq 'error') {
119     printline (status => [4, 'INFO: ' . $data->{message}]);
120     }
121    
122     printline (debug => [0, JSON::Syck::Dump ($data)]);
123     },
124     disconnect_cb => sub {
125     printline (status => [4, "ERROR: " . $_[0]]);
126 elmex 1.2 }
127 elmex 1.6 );
128 elmex 1.1
129     $js->connect (localhost => 1236);
130    
131 elmex 1.2 CursesChatMainwindow::init;
132 elmex 1.1
133 elmex 1.3 printline (status => ['p0', 0, "Connected!"]);
134     printline (statusline => [20, "Welcome to the json enhanced chat framework!"]);
135 elmex 1.2
136 elmex 1.4 sub find_common_prefix {
137     my (@words) = @_;
138     @words = sort { length ($a) <=> length ($b) } @words;
139     my $shortest = $words[0];
140    
141     while ($shortest ne '') {
142     my $no_match = 0;
143     for (@words) {
144     unless (/^\Q$shortest\E/) {
145     $no_match = 1;
146     last;
147     }
148     }
149    
150     return $shortest if not $no_match;
151     substr $shortest, -1, 1, '';
152     }
153    
154     return '';
155     }
156    
157     CursesChatMainwindow::register_complete_cb (sub {
158     my ($word, $first_compl, $idx, @line) = @_;
159    
160     # TODO: make completion cycling with $first_compl
161 elmex 1.6 printline (undef, [0, "f[$first_compl] [$idx] [$word]"]);
162 elmex 1.4
163     my @found;
164 elmex 1.6
165 elmex 1.4 if ($idx == 0) {
166     for (keys %completion) {
167     if (/^\Q$word\E/) {
168     push @found, $_;
169     }
170     }
171 elmex 1.6
172 elmex 1.4 } else {
173     my %buffers = map { $_ => 1 } list_buffers;
174 elmex 1.6
175     for (keys %rev_known_ids) {
176 elmex 1.4 delete $buffers{$_};
177     if (/^\Q$word\E/) {
178     push @found, $_;
179     }
180     }
181 elmex 1.6
182 elmex 1.4 for (keys %buffers) {
183     if (/^\Q$word\E/) {
184     push @found, $_;
185     }
186     }
187     }
188 elmex 1.6
189 elmex 1.4 return "$found[0] " if @found == 1;
190 elmex 1.6
191 elmex 1.4 if (@found) {
192     printline (undef, [0, "$word: " . join ", ", @found]);
193     return find_common_prefix (@found);
194     }
195    
196     return $word;
197     });
198    
199 elmex 1.2 CursesChatMainwindow::register_input_cb (sub {
200 elmex 1.3 my ($input, $escape) = @_;
201    
202     unless (defined $input) {
203     if (exists $CFG->{buffers}->{$escape}) {
204 elmex 1.6 change_buffer (my $buf = $CFG->{buffers}->{$escape} || 'status');
205 elmex 1.3 printline (statusline => [20, "[$buf]"]);
206 elmex 1.2 } else {
207 elmex 1.6 change_buffer ('status');
208 elmex 1.3 printline (statusline => [20, "[status]"]);
209 elmex 1.1 }
210 elmex 1.3 return;
211     }
212    
213 elmex 1.4 if ($input =~ m/^\/buffer\s*(\S+)/) {
214 elmex 1.6 change_buffer ("$1");
215 elmex 1.3 printline (statusline => [20, "[$1]"]);
216 elmex 1.6
217 elmex 1.4 } elsif ($input =~ m/^\/list_buffers/) {
218     printline (undef, [0, "buffers:"]);
219     for (list_buffers) {
220     printline (undef, [0, "- $_"]);
221     }
222 elmex 1.6
223 elmex 1.2 } elsif ($input =~ m/^\/colors/) {
224     CursesChatMainwindow::print_colors;
225 elmex 1.6
226     } elsif ($input =~ m/^\/reconnect\s*(\S*)\s*(\S*)/) {
227     $js->connect ($1 || 'localhost', $2 || 1236);
228     printline (status => [3, "reconnected"]);
229    
230     } elsif ($input =~ m/^\/reload/) {
231     load_cfg ();
232    
233     } elsif ($input =~ m/^\/remote_reload/) {
234     $js->send_data ({ type => 'command', command => 'reload' });
235    
236 elmex 1.2 } else {
237 elmex 1.6 my $pret_id = "" . current_buffer ();
238     my $dest_id = $rev_known_ids{$pret_id};
239    
240 elmex 1.4 my $msg = {
241 elmex 1.3 type => 'message',
242 elmex 1.4 dest => $dest_id,
243 elmex 1.2 message => $input
244 elmex 1.4 };
245     $js->send_data ($msg);
246     printline (debug => [0, JSON::Syck::Dump ($msg)]);
247 elmex 1.6 my $mynick = $known_ids{$dest_id}->{send_id} ? prettyfy_id ($known_ids{$dest_id}->{send_id}) : "";
248     write_chatline ($pret_id, $mynick, time, $input, 'local');
249 elmex 1.1 }
250 elmex 1.2 });
251 elmex 1.1
252     $c->wait;
253    
254 elmex 1.2 CursesChatMainwindow::end;