diff options
Diffstat (limited to 'lib/DJabberd/RosterStorage/SQLite')
-rw-r--r-- | lib/DJabberd/RosterStorage/SQLite/Fixed.pm | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/lib/DJabberd/RosterStorage/SQLite/Fixed.pm b/lib/DJabberd/RosterStorage/SQLite/Fixed.pm new file mode 100644 index 0000000..fe41363 --- /dev/null +++ b/lib/DJabberd/RosterStorage/SQLite/Fixed.pm | |||
@@ -0,0 +1,274 @@ | |||
1 | package DJabberd::RosterStorage::SQLite::Fixed; | ||
2 | use strict; | ||
3 | use warnings; | ||
4 | use base 'DJabberd::RosterStorage::SQLite'; | ||
5 | use DJabberd::Log; | ||
6 | use DJabberd::Util; | ||
7 | our $logger = DJabberd::Log->get_logger(); | ||
8 | |||
9 | =head1 NAME | ||
10 | |||
11 | DJabberd::RosterStorage::SQLite::Fixed - a shared roster implementation for the SQLite roster storage | ||
12 | |||
13 | =head1 VERSION | ||
14 | |||
15 | Version 0.02 | ||
16 | =cut | ||
17 | |||
18 | our $VERSION = '0.02'; | ||
19 | |||
20 | =head1 SYNOPSIS | ||
21 | |||
22 | <VHost mydomain.com> | ||
23 | |||
24 | [...] | ||
25 | |||
26 | <Plugin DJabberd::RosterStorage::SQLite::Fixed> | ||
27 | Database jabberroster.sqlite | ||
28 | FixedGuestOK yes | ||
29 | </Plugin> | ||
30 | </VHost> | ||
31 | |||
32 | Valid command are all command valid in DJabberd::RosterStorage::SQLite Plus the following | ||
33 | |||
34 | FixedGuestOK - Populate accounts with the shared roster if they are not in the roster itself? | ||
35 | Setting this to yes will populate a user who is not in the shared roster with everyone in the shared roster | ||
36 | The default is to only populate rosters for users that are part of the shared roster | ||
37 | |||
38 | =head1 AUTHOR | ||
39 | |||
40 | Edward Rudd, C<< <urkle at outoforder.cc> >> | ||
41 | |||
42 | =cut | ||
43 | |||
44 | =head2 set_config_fixedguestok($self, $guest) | ||
45 | |||
46 | Called to specify if guests should have the shared roster added to their roster | ||
47 | |||
48 | =cut | ||
49 | |||
50 | sub set_config_fixedguestok { | ||
51 | my ($self, $guest) = @_; | ||
52 | $self->{fixed_guestok} = as_bool $guest; | ||
53 | } | ||
54 | |||
55 | =head2 finalize($self) | ||
56 | |||
57 | Set defaults for the configuration | ||
58 | |||
59 | =cut | ||
60 | |||
61 | sub finalize { | ||
62 | my $self = shift; | ||
63 | $self->{fixed_guestok} = 0 unless $self->{fixed_guestok}; | ||
64 | $self->SUPER::finalize; | ||
65 | } | ||
66 | |||
67 | =head2 get_roster($self, $cb, $jid) | ||
68 | |||
69 | Gets the Roster for the user | ||
70 | |||
71 | =cut | ||
72 | |||
73 | sub get_roster { | ||
74 | my ($self, $cb, $jid) = @_; | ||
75 | # cb can '->set_roster(Roster)' or decline | ||
76 | |||
77 | my $myself = lc $jid->as_bare_string; | ||
78 | $logger->info("Fixed loading roster for $myself ..."); | ||
79 | |||
80 | my $on_load_roster = sub { | ||
81 | my (undef, $roster) = @_; | ||
82 | |||
83 | my $pre_ct = $roster->items; | ||
84 | $logger->info(" $pre_ct roster items prior to population..."); | ||
85 | |||
86 | # see which shared contacts already in roster | ||
87 | my %has; | ||
88 | foreach my $it ($roster->items) { | ||
89 | my $jid = $it->jid; | ||
90 | $has{lc $jid->as_bare_string} = $it; | ||
91 | } | ||
92 | |||
93 | # add missing shared contacts to the roster | ||
94 | my $req_roster = $self->_roster(); | ||
95 | if ($self->{fixed_guestok}==0) { | ||
96 | my $guestok = 0; | ||
97 | foreach my $user ( @$req_roster) { | ||
98 | if ($user->{jid} eq $myself) { | ||
99 | $guestok = 1; | ||
100 | last; | ||
101 | } | ||
102 | } | ||
103 | # Bail if guestOK == 0 && user it not in the roster | ||
104 | return if $guestok == 0; | ||
105 | } | ||
106 | |||
107 | foreach my $user ( @$req_roster) { | ||
108 | next if $user->{jid} eq $myself; | ||
109 | |||
110 | my $name = $user->{name}; | ||
111 | my $ri = $has{$user->{jid}} || DJabberd::RosterItem->new(jid => $user->{jid}, | ||
112 | name => ($user->{name} || $user->{jid}), | ||
113 | groups => [$user->{group}]); | ||
114 | |||
115 | |||
116 | $ri->subscription->set_from; | ||
117 | $ri->subscription->set_to; | ||
118 | $roster->add($ri); | ||
119 | } | ||
120 | |||
121 | my $post_ct = $roster->items; | ||
122 | $logger->info(" $post_ct roster items post population..."); | ||
123 | |||
124 | $cb->set_roster($roster); | ||
125 | }; | ||
126 | |||
127 | my $cb2 = DJabberd::Callback->new({set_roster => $on_load_roster, | ||
128 | decline => sub { $cb->decline }}); | ||
129 | $self->SUPER::get_roster($cb2, $jid); | ||
130 | } | ||
131 | |||
132 | =head2 check_install_schema($self) | ||
133 | |||
134 | Checks the SQL ite Schema | ||
135 | |||
136 | =cut | ||
137 | |||
138 | sub check_install_schema { | ||
139 | my $self = shift; | ||
140 | |||
141 | $self->SUPER::check_install_schema(); | ||
142 | |||
143 | my $dbh = $self->{dbh}; | ||
144 | |||
145 | eval { | ||
146 | $dbh->do(qq{ | ||
147 | CREATE TABLE requiredusers ( | ||
148 | jid VARCHAR(255) NOT NULL, | ||
149 | fullname VARCHAR(255) NOT NULL, | ||
150 | groupname VARCHAR(255) NOT NULL, | ||
151 | UNIQUE (jid) | ||
152 | )}); | ||
153 | }; | ||
154 | if ($@ && $@ !~ /table \w+ already exists/) { | ||
155 | $logger->logdie("SQL error $@"); | ||
156 | die "SQL error: $@\n"; | ||
157 | } | ||
158 | eval { | ||
159 | $dbh->do(qq{ | ||
160 | CREATE VIEW RosterPreview AS | ||
161 | SELECT ju.jid AS UserID, g.name AS [Group], | ||
162 | jr.jid AS ContactID, r.name AS Contact, r.subscription AS Subscription | ||
163 | FROM roster r | ||
164 | JOIN jidmap ju ON r.userid=ju.jidid | ||
165 | JOIN jidmap jr ON r.contactid = jr.jidid | ||
166 | JOIN groupitem gi ON gi.contactid=r.contactid | ||
167 | JOIN rostergroup g ON g.userid=r.userid AND g.groupid=gi.groupid | ||
168 | UNION SELECT r1.jid, r2.groupname, r2.jid, r2.fullname, 3 | ||
169 | FROM requiredusers r1, requiredusers r2 | ||
170 | WHERE r1.jid != r2.jid}); | ||
171 | }; | ||
172 | if ($@ && $@ !~ /table \w+ already exists/) { | ||
173 | $logger->logdie("SQL error $@"); | ||
174 | die "SQL error: $@\n"; | ||
175 | } | ||
176 | eval { | ||
177 | $dbh->do(qq{ | ||
178 | CREATE VIEW RosterList AS | ||
179 | SELECT J.jidid as LID, J2.jidid as RID, | ||
180 | G.groupid as GID, | ||
181 | J.jid AS Local, J2.jid AS Remote, | ||
182 | G.name AS [Group] | ||
183 | FROM jidmap J | ||
184 | JOIN rostergroup G ON G.userid=J.jidid | ||
185 | JOIN groupitem M ON G.groupid = M.groupid | ||
186 | JOIN jidmap J2 ON J2.jidid = M.contactid | ||
187 | ORDER BY J.jid, J2.jid}); | ||
188 | }; | ||
189 | if ($@ && $@ !~ /table \w+ already exists/) { | ||
190 | $logger->logdie("SQL error $@"); | ||
191 | die "SQL error: $@\n"; | ||
192 | } | ||
193 | $logger->info("Created all roster tables"); | ||
194 | } | ||
195 | |||
196 | my $last_roster; | ||
197 | my $last_roster_time = 0; # unixtime of last SQL suck | ||
198 | sub _roster { | ||
199 | my $self = shift; | ||
200 | my $now = time(); | ||
201 | |||
202 | # Cache list for 1 minute(s) | ||
203 | if ($last_roster && $last_roster_time > $now - 60) { | ||
204 | return $last_roster; | ||
205 | } | ||
206 | |||
207 | my $dbh = $self->{dbh}; | ||
208 | |||
209 | my $sql = qq{ | ||
210 | SELECT jid, fullname, groupname FROM requiredusers | ||
211 | }; | ||
212 | |||
213 | my $roster = eval { | ||
214 | $dbh->selectall_arrayref($sql); | ||
215 | }; | ||
216 | $logger->logdie("Failed to load roster: $@") if $@; | ||
217 | |||
218 | $logger->info("Found ".($#{ @$roster}+1)." Roster users"); | ||
219 | |||
220 | my @info = (); | ||
221 | foreach my $item ( @$roster ) { | ||
222 | my $rec = {}; | ||
223 | $rec->{'jid'} = $item->[0]; | ||
224 | $rec->{'name'} = $item->[1]; | ||
225 | $rec->{'group'} = $item->[2]; | ||
226 | push @info, $rec; | ||
227 | } | ||
228 | $logger->info("Loaded ".($#info+1)." Roster users"); | ||
229 | $last_roster_time = $now; | ||
230 | return $last_roster = \@info; | ||
231 | } | ||
232 | |||
233 | =head2 load_roster_item($self, $jid, $contact_jid, $cb) | ||
234 | |||
235 | Called when a roster item is added | ||
236 | |||
237 | =cut | ||
238 | |||
239 | sub load_roster_item { | ||
240 | my ($self, $jid, $contact_jid, $cb) = @_; | ||
241 | |||
242 | my $is_shared = sub { | ||
243 | my $jid = shift; | ||
244 | my $roster = $self->_roster(); | ||
245 | foreach my $user (@$roster) { | ||
246 | if (lc $user->{jid} eq lc $jid->as_bare_string) { return 1; } | ||
247 | } | ||
248 | return 0; | ||
249 | }; | ||
250 | |||
251 | if ($is_shared->($jid) && $is_shared->($contact_jid)) { | ||
252 | my $both = DJabberd::Subscription->new; | ||
253 | $both->set_from; | ||
254 | $both->set_to; | ||
255 | my $rit = DJabberd::RosterItem->new(jid => $contact_jid, | ||
256 | subscription => $both); | ||
257 | $cb->set($rit); | ||
258 | return; | ||
259 | } | ||
260 | |||
261 | $self->SUPER::load_roster_item($jid, $contact_jid, $cb); | ||
262 | } | ||
263 | |||
264 | =head1 COPYRIGHT & LICENSE | ||
265 | |||
266 | Original work Copyright 2006 Alexander Karelas, Martin Atkins, Brad Fitzpatrick and Aleksandar Milanov. All rights reserved. | ||
267 | Copyright 2007 Edward Rudd. All rights reserved. | ||
268 | |||
269 | This program is free software; you can redistribute it and/or modify it | ||
270 | under the same terms as Perl itself. | ||
271 | |||
272 | =cut | ||
273 | |||
274 | 1; | ||