html/centericq.pl
1 # $Id: centericq.pl,v 1.0.0 2002/10/19 13:15:49 Garion Exp $
2
3 $VERSION = "1.0.0";
4 %IRSSI = (
5 authors => "Joost \"Garion\" Vunderink",
6 contact => "joost\@carnique.nl",
7 name => "centericq",
8 description => "Staturbar item which indicates how many new messages you have in your centericq",
9 license => "Public Domain",
10 url => "http://irssi.org, http://scripts.irssi.org",
11 );
12
13 # centericq new messages statusbar item
14 # for irssi 0.8.4 by Timo Sirainen
15 #
16 # This statusbar item checks whether you have unread messages in
17 # ~/.centericq/, and if so, displays a status in your statusbar.
18 # Example status: [ICQ: JamesOff-1,Linn-3,Paul-4]
19 #
20 # Use:
21 # /script load centericq
22 # /statusbar <name> add centericq
23 #
24 # Known bugs:
25 # - It only works for ICQ and MSN in centericq.
26 # - The refreshing is not optimal. You'll need to swap windows to make
27 # the statusbar item disappear if you've read the messages.
28 # - You have to reload the script if you add new people in centericq.
29 # - Works only with centericq in ~/.centericq/
30 #
31 # TODO:
32 # - Use only the first N letters of the nickname instead of the full
33 # nickname.
34
35 use Irssi;
36 use Irssi::TextUI;
37
38 my $icqdir = $ENV{'HOME'} . "/.centericq";
39 my ($last_refresh_time, $refresh_tag);
40 my $statusbar_item;
41
42 # The following vars are all hashes with key the name of the dir in
43 # ~/.centericq/ of that person
44
45 my %lastreads; # Timestamp of the last read message, per nick
46 my %numunreads; # Number of unread messages, per nick
47 my %historyts; # Timestamp of the history file of each nick
48 my %lastreadts; # Timestamp of the lastread file of each nick
49 my %friendnicks; # The nicknames of the friends
50
51
52 #######################################################################
53 # This is the function that will be called each N seconds, where
54 # N is given by the centericq_refresh_time setting.
55
56 sub refresh_centericq {
57 check_new_friends();
58
59 my @friends = keys(%lastreads);
60 my ($friend, $changed) = ("", 0);
61 foreach $friend (@friends) {
62 if (history_changed($friend) || lastread_changed($friend)) {
63 $changed = 1;
64 update_status($friend);
65 }
66 }
67
68 if ($changed) {
69 update_statusbar_item();
70 }
71
72 # Adding new timeout to make sure that this function will be called
73 # again
74 if ($refresh_tag) {
75 Irssi::timeout_remove($refresh_tag)
76 }
77 my $time = Irssi::settings_get_int('centericq_refresh_time');
78 $refresh_tag = Irssi::timeout_add($time*1000, 'refresh_centericq', undef);
79 }
80
81
82 #######################################################################
83 # Checks if any new friends have been added. Not yet functional.
84
85 sub check_new_friends {
86 #Irssi::print("Checking if there are any new friends...");
87 }
88
89 #######################################################################
90 # Checks if the last modified date/time of the lastread file has changed.
91 # A -lot- more efficient than reading and processing the whole file :)
92
93 sub lastread_changed {
94 my ($friend) = @_;
95
96 my $lr = get_lastread($friend);
97 if ($lr != $lastreads{$friend}) {
98 #Irssi::print("Lastread of $friendnick{$friend} changed from $lastreads{$friend} to $lr.");
99 $lastreads{$friend} = $lr;
100 return 1;
101 }
102
103 return 0;
104 }
105
106 #######################################################################
107 # Checks if the last modified date/time of the history file has changed.
108 # A -lot- more efficient than reading and processing the whole file :)
109
110 sub history_changed {
111 my ($friend) = @_;
112 my $ts = get_historyts($friend);
113 if ($ts != $historyts{$friend}) {
114 #Irssi::print("History ts of $friendnick{$friend} changed from $historyts{$friend} to $ts.");
115 $historyts{$friend} = $ts;
116 return 1;
117 }
118
119 return 0;
120 }
121
122 #######################################################################
123 # Reads the last read message and determines the number of unread
124 # messages of $friend.
125
126 sub update_status {
127 my ($friend) = @_;
128 $lastreads{$friend} = get_lastread($friend);
129 $numunreads{$friend} = get_numunreads($friend);
130 }
131
132 #######################################################################
133 # Gets the number of unread messages of all nicks and puts them together
134 # in a nice statusbar string.
135 # It then requests a statusbar item redraw.
136
137 sub update_statusbar_item {
138 #Irssi::print("Updating statusbaritem...");
139 $statusbar_item = "";
140
141 my @keys = keys(%lastreads);
142 my ($key, $status);
143
144 foreach $key(@keys) {
145 if ($numunreads{$key} > 0) {
146 #Irssi::print("$friendnick{$key} has $numunreads{$key} unreads.");
147 $status .= $friendnick{$key} . "-" . $numunreads{$key} . ",";
148 }
149 }
150 $status =~ s/,$//;
151 if (length($status) > 0) {
152 $statusbar_item = "ICQ: " . $status;
153 Irssi::statusbar_items_redraw('centericq');
154 }
155 }
156
157
158 #######################################################################
159 # This is the function called by irssi to obtain the statusbar item
160 # for centericq.
161
162 sub centericq {
163 my ($item, $get_size_only) = @_;
164
165 if (length($statusbar_item) == 0) {
166 # no icq - don't print the [ICQ] at all
167 if ($get_size_only) {
168 $item->{min_size} = $item->{max_size} = 0;
169 }
170 } else {
171 $item->default_handler($get_size_only, undef, $statusbar_item, 1);
172 }
173 }
174
175 #######################################################################
176 # Initialization of the hashes with the useful data.
177
178 sub init {
179 if (!opendir(ICQDIR, $icqdir)) {
180 Irssi::print("There is no directory $icqdir, which is needed for this script.");
181 return 0;
182 }
183
184 my ($icqfriends, $msnfriends) = (0, 0);
185 while ($filename = readdir(ICQDIR)) {
186 # ICQ friends
187 if ($filename =~ /^[0-9]+$/ && $filename !~ /^0$/) {
188 $icqfriends++;
189 init_friend($filename);
190 }
191 # MSN friends
192 if ($filename =~ /^m.+/ && $filename !~ /^modelist$/ ) {
193 $msnfriends++;
194 init_friend($filename);
195 }
196 }
197 Irssi::print("Watching $icqfriends ICQ friends and $msnfriends MSN friends.");
198
199 closedir(ICQDIR);
200 return 1;
201 }
202
203 #######################################################################
204 # Initialises all data of $friend
205
206 sub init_friend {
207 my ($friend) = @_;
208
209 $lastreads{$friend} = get_lastread($friend);
210 $numunreads{$friend} = get_numunreads($friend);
211 #$filesizes{$friend} = get_filesize($friend);
212 $friendnick{$friend} = get_nickname($friend);
213 $historyts{$friend} = get_historyts($friend);
214 #Irssi::print("Initilialized $friendnick{$friend}.");
215 }
216
217 #######################################################################
218 # Returns the last read message of $friend
219
220 sub get_lastread {
221 my ($friend) = @_;
222 my $lastreadfile = $icqdir . "/" . $friend . "/lastread";
223
224 open(F, "<$lastreadfile") || return 0; #die("Could not open $lastreadfile.");;
225 my $lastrd = <F>;
226 close(F);
227 chop($lastrd);
228 #Irssi::print("Found lastread $lastrd of $friend from $lastreadfile.");
229
230 return $lastrd;
231 }
232
233 #######################################################################
234 # Returns the number of unread messages for $friend
235
236 sub get_numunreads {
237 my ($friend) = @_;
238 my $lr = $lastreads{$friend};
239 # Unknown last read message - return 0.
240 if ($lr == 0) {
241 return 0;
242 }
243
244 my $msgfile = $icqdir . "/" . $friend . "/history";
245 open(F, "<$msgfile") || return 0; #die("Could not open $msgfile.");
246 my @lines = <F>;
247 chop(@lines);
248 close(F);
249
250 my $numlines = @lines;
251
252 # read all lines up to the lastread message
253 my $line;
254 my $bla = 0;
255 do {
256 $line = shift(@lines);
257 $bla++;
258 } while ($line ne $lr);
259
260 # now count the number of times that "MSG" is found on a line below
261 # a line with "IN"
262 my $count = 0;
263 my $incoming = 0;
264 my $verify = 0;
265 my $bli = 0;
266
267 for (@lines) {
268 $bli++;
269 # Sometimes 2 messages get in at the same time. Remove this so-called
270 # new message if it has the same time as the last read message.
271 if ($verify == 1) {
272 if ($_ =~ /$lr/) {
273 $count--;
274 }
275 $verify = 0;
276 }
277 # A line with "IN" has been found; check if the next line is "MSG".
278 if ($incoming == 1) {
279 if ($_ =~ /^MSG/) {
280 $count++;
281 $verify = 1;
282 }
283 $incoming = 0;
284 }
285 # Check for "IN".
286 if ($_ =~ /^IN/) {
287 $incoming = 1;
288 }
289 }
290
291 return $count;
292 }
293
294 #######################################################################
295 # Returns the nickname of a friend. This is taken from the 46th line
296 # of the info file. Let's hope that centericq does not change its
297 # config file format.
298
299 sub get_nickname {
300 my ($friend) = @_;
301
302 my $infofile = $icqdir . "/" . $friend . "/info";
303 open(F, "<$infofile") || return $friend; #die("Could not open $msgfile.");
304 my @lines = <F>;
305 chop(@lines);
306 close(F);
307
308 return $lines[45];
309 }
310
311 #######################################################################
312 # Returns the timestamp of the history file of $friend.
313
314 sub get_historyts {
315 my ($friend) = @_;
316 my $histfile = $icqdir . "/" . $friend . "/history";
317 my @stat = stat($histfile);
318 return $stat[9];
319 }
320
321 #######################################################################
322 # Adding stuff to irssi
323
324 Irssi::settings_add_int('misc', 'centericq_refresh_time', 120);
325 #Irssi::settings_add_bool('misc', 'centericq_debug', 0);
326 Irssi::statusbar_item_register('centericq', '{sb $0-}', 'centericq');
327
328 #######################################################################
329 # Startup functions
330
331 if (init() == 0) {
332 Irssi::print("You need centericq for this script.");
333 return 0;
334 }
335 update_statusbar_item();
336 refresh_centericq();
337
338 Irssi::print("Centericq statusbar item loaded.");
339
340 #######################################################################