2
* $Id: xmpp-rosters.c,v 1.22 2008/04/05 20:50:45 errtu Exp $
4
* Copyright (C) 2007 Colin DIDIER
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License version 2 as
8
* published by the Free Software Foundation.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License along
16
* with this program; if not, write to the Free Software Foundation, Inc.,
17
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27
#include "xmpp-servers.h"
28
#include "xmpp-rosters.h"
29
#include "xmpp-rosters-tools.h"
30
#include "xmpp-tools.h"
32
const char *xmpp_presence_show[] = {
44
const char *xmpp_subscription[] = {
54
func_find_group(gconstpointer group, gconstpointer name)
56
char *group_name = ((XMPP_ROSTER_GROUP_REC *)group)->name;
58
if (group_name == name)
60
if (group_name == NULL || name == NULL)
62
return strcmp(group_name, name);
66
func_sort_group(gconstpointer group1, gconstpointer group2)
68
char *group1_name, *group2_name;
70
group1_name = ((XMPP_ROSTER_GROUP_REC *)group1)->name;
71
group2_name = ((XMPP_ROSTER_GROUP_REC *)group2)->name;
72
if (group1_name == NULL || (group2_name != NULL
73
&& strcmp(group2_name,
74
settings_get_str("roster_service_name")) == 0))
76
if (group1_name != NULL || (group2_name == NULL
77
&& strcmp(group1_name,
78
settings_get_str("roster_service_name")) == 0))
80
return strcmp(group1_name, group2_name);
84
func_sort_resource(gconstpointer resource1, gconstpointer resource2)
86
return ((XMPP_ROSTER_RESOURCE_REC *)resource2)->priority
87
- ((XMPP_ROSTER_RESOURCE_REC *)resource1)->priority;
90
static XMPP_ROSTER_RESOURCE_REC *
91
create_resource(const char *name)
93
XMPP_ROSTER_RESOURCE_REC *resource;
95
resource = g_new(XMPP_ROSTER_RESOURCE_REC, 1);
97
resource->name = g_strdup(name);
98
resource->priority = 0;
99
resource->show= XMPP_PRESENCE_UNAVAILABLE;
100
resource->status = NULL;
101
resource->composing_id = NULL;
107
cleanup_resource(gpointer data, gpointer user_data)
109
XMPP_ROSTER_RESOURCE_REC *resource;
113
resource = (XMPP_ROSTER_RESOURCE_REC *)data;
115
g_free(resource->name);
116
g_free(resource->status);
117
g_free(resource->composing_id);
121
static XMPP_ROSTER_USER_REC *
122
create_user(const char *jid, const char *name)
124
XMPP_ROSTER_USER_REC *user;
126
g_return_val_if_fail(jid != NULL, NULL);
128
user = g_new(XMPP_ROSTER_USER_REC, 1);
130
user->jid = g_strdup(jid);
131
user->name = g_strdup(name);
132
user->subscription = XMPP_SUBSCRIPTION_NONE;
134
user->resources = NULL;
140
cleanup_user(gpointer data, gpointer user_data)
142
XMPP_ROSTER_USER_REC *user;
146
user = (XMPP_ROSTER_USER_REC *)data;
148
g_slist_foreach(user->resources, (GFunc)cleanup_resource, NULL);
149
g_slist_free(user->resources);
156
static XMPP_ROSTER_GROUP_REC *
157
create_group(const char *name)
159
XMPP_ROSTER_GROUP_REC *group = g_new(XMPP_ROSTER_GROUP_REC, 1);
161
group->name = g_strdup(name);
168
cleanup_group(gpointer data, gpointer user_data)
170
XMPP_ROSTER_GROUP_REC *group;
174
group = (XMPP_ROSTER_GROUP_REC *)data;
176
g_slist_foreach(group->users, (GFunc)cleanup_user, group);
177
g_slist_free(group->users);
184
sig_cleanup(XMPP_SERVER_REC *server)
186
if (!IS_XMPP_SERVER(server))
189
if (server->roster == NULL)
192
g_slist_foreach(server->roster, (GFunc)cleanup_group, server);
193
g_slist_free(server->roster);
194
server->roster = NULL;
196
g_slist_foreach(server->resources, (GFunc)cleanup_resource, NULL);
197
g_slist_free(server->resources);
198
server->resources = NULL;
201
static XMPP_ROSTER_GROUP_REC *
202
find_or_add_group(XMPP_SERVER_REC *server, const char *group_name)
205
XMPP_ROSTER_GROUP_REC *group;
207
g_return_val_if_fail(IS_XMPP_SERVER(server), NULL);
209
group_list = g_slist_find_custom(server->roster, group_name,
210
(GCompareFunc)func_find_group);
212
/* group doesn't exist */
213
if (group_list == NULL) {
214
group = create_group(group_name);
215
server->roster = g_slist_insert_sorted(server->roster, group,
216
(GCompareFunc)func_sort_group);
218
group = group_list->data;
223
static XMPP_ROSTER_USER_REC *
224
add_user(XMPP_SERVER_REC *server, const char *jid, const char *name,
225
const char *group_name, XMPP_ROSTER_GROUP_REC **group)
227
XMPP_ROSTER_USER_REC *user;
229
g_return_val_if_fail(IS_XMPP_SERVER(server), NULL);
230
g_return_val_if_fail(jid != NULL, NULL);
232
*group = find_or_add_group(server, group_name);
234
user = create_user(jid, name);
235
(*group)->users = g_slist_append((*group)->users, user);
240
static XMPP_ROSTER_GROUP_REC *
241
move_user(XMPP_SERVER_REC *server, XMPP_ROSTER_USER_REC *user,
242
XMPP_ROSTER_GROUP_REC *group, const char *group_name)
244
XMPP_ROSTER_GROUP_REC *new_group;
246
g_return_val_if_fail(IS_XMPP_SERVER(server), group);
247
g_return_val_if_fail(user != NULL, group);
249
new_group = find_or_add_group(server, group_name);
251
group->users = g_slist_remove(group->users, user);
252
new_group->users = g_slist_append(new_group->users, user);
258
update_subscription(XMPP_SERVER_REC *server, XMPP_ROSTER_USER_REC *user,
259
XMPP_ROSTER_GROUP_REC *group, const char *subscription)
261
g_return_if_fail(IS_XMPP_SERVER(server));
262
g_return_if_fail(user != NULL);
263
g_return_if_fail(group != NULL);
264
g_return_if_fail(subscription != NULL);
266
if (g_ascii_strcasecmp(subscription,
267
xmpp_subscription[XMPP_SUBSCRIPTION_NONE]) == 0)
268
user->subscription = XMPP_SUBSCRIPTION_NONE;
270
else if (g_ascii_strcasecmp(subscription,
271
xmpp_subscription[XMPP_SUBSCRIPTION_FROM]) == 0)
272
user->subscription = XMPP_SUBSCRIPTION_FROM;
274
else if (g_ascii_strcasecmp(subscription,
275
xmpp_subscription[XMPP_SUBSCRIPTION_TO]) == 0)
276
user->subscription = XMPP_SUBSCRIPTION_TO;
278
else if (g_ascii_strcasecmp(subscription,
279
xmpp_subscription[XMPP_SUBSCRIPTION_BOTH]) == 0)
280
user->subscription = XMPP_SUBSCRIPTION_BOTH;
282
else if (g_ascii_strcasecmp(subscription,
283
xmpp_subscription[XMPP_SUBSCRIPTION_REMOVE]) == 0) {
284
group->users = g_slist_remove(group->users, user);
285
cleanup_user(user, server);
287
/* remove empty group */
288
if (group->users == NULL) {
289
server->roster = g_slist_remove(server->roster, group);
290
cleanup_group(group, server);
296
update_user(XMPP_SERVER_REC *server, const char *jid, const char *subscription,
297
const char *name, const char *group_name)
299
XMPP_ROSTER_GROUP_REC *group;
300
XMPP_ROSTER_USER_REC *user;
302
g_return_if_fail(IS_XMPP_SERVER(server));
303
g_return_if_fail(jid != NULL);
305
user = xmpp_rosters_find_user(server->roster, jid, &group, NULL);
307
user = add_user(server, jid, name, group_name, &group);
310
/* move to another group */
311
if ((group->name == NULL && group_name != NULL)
312
|| (group->name != NULL && group_name == NULL)
313
|| (group->name != NULL && group_name != NULL
314
&& strcmp(group->name, group_name) != 0))
315
group = move_user(server, user, group, group_name);
318
if ((user->name == NULL && name != NULL)
319
|| (user->name != NULL && name == NULL)
320
|| (user->name != NULL && name != NULL
321
&& strcmp(user->name, name) != 0)) {
323
user->name = g_strdup(name);
327
update_subscription(server, user, group, subscription);
331
sig_update(XMPP_SERVER_REC *server, LmMessageNode *query)
333
LmMessageNode *item, *group_node;
334
const char *subscription, *jid, *name;
335
char *jid_recoded, *name_recoded, *group_recoded;
337
g_return_if_fail(IS_XMPP_SERVER(server));
338
g_return_if_fail(query != NULL);
341
group_recoded = NULL;
343
item = query->children;
344
while(item != NULL) {
346
if (g_ascii_strcasecmp(item->name, "item") != 0)
349
jid = lm_message_node_get_attribute(item, "jid");
352
jid_recoded = xmpp_recode_in(jid);
354
subscription = lm_message_node_get_attribute(item,
357
name = lm_message_node_get_attribute(item, "name");
359
name_recoded = xmpp_recode_in(name);
361
group_node = lm_message_node_get_child(item, "group");
362
if (group_node != NULL)
363
group_recoded = xmpp_recode_in(group_node->value);
365
update_user(server, jid_recoded, subscription, name_recoded,
368
g_free_and_null(jid_recoded);
369
g_free_and_null(name_recoded);
370
g_free_and_null(group_recoded);
378
sig_presence_update(XMPP_SERVER_REC *server, const char *full_jid,
379
const char *show_str, const char *status, const char *priority_str)
381
XMPP_ROSTER_USER_REC *user;
382
XMPP_ROSTER_RESOURCE_REC *resource;
387
g_return_if_fail(IS_XMPP_SERVER(server));
388
g_return_if_fail(full_jid != NULL);
391
jid = xmpp_strip_resource(full_jid);
392
res = xmpp_extract_resource(full_jid);
394
user = xmpp_rosters_find_user(server->roster, jid, NULL, NULL);
397
else if (strcmp(jid, server->jid) == 0)
402
/* find resource or create it if it doesn't exist */
403
resource = !own ? xmpp_rosters_find_resource(user, res) :
404
xmpp_rosters_find_own_resource(server, res);
405
if (resource == NULL) {
406
resource = create_resource(res);
410
g_slist_prepend(user->resources, resource);
413
g_slist_prepend(server->resources, resource);
416
show = xmpp_presence_get_show(show_str);
418
priority = (priority_str != NULL) ?
419
atoi(priority_str) : resource->priority;
421
if (new || xmpp_presence_changed(show, resource->show, status,
422
resource->status, priority, resource->priority)) {
424
resource->show = show;
426
g_free_and_null(resource->status);
428
resource->status = g_strdup(status);
430
if (resource->priority != priority) {
431
resource->priority = priority;
433
/* the resource has changed, sort the resources */
435
user->resources = g_slist_sort(
437
(GCompareFunc)func_sort_resource);
439
server->resources = g_slist_sort(
441
(GCompareFunc)func_sort_resource);
444
signal_emit("xmpp presence changed", 5, server, full_jid,
445
resource->show, resource->status, resource->priority);
454
sig_presence_error(XMPP_SERVER_REC *server, const char *full_jid)
456
XMPP_ROSTER_USER_REC *user;
459
g_return_if_fail(IS_XMPP_SERVER(server));
460
g_return_if_fail(full_jid != NULL);
462
jid = xmpp_strip_resource(full_jid);
464
user = xmpp_rosters_find_user(server->roster, jid, NULL, NULL);
474
sig_presence_unavailable(XMPP_SERVER_REC *server, const char *full_jid,
477
XMPP_ROSTER_USER_REC *user;
478
XMPP_ROSTER_RESOURCE_REC *resource;
482
g_return_if_fail(IS_XMPP_SERVER(server));
483
g_return_if_fail(full_jid != NULL);
486
jid = xmpp_strip_resource(full_jid);
487
res = xmpp_extract_resource(full_jid);
489
user = xmpp_rosters_find_user(server->roster, jid, NULL, NULL);
491
if (strcmp(jid, server->jid) == 0)
497
resource = !own ? xmpp_rosters_find_resource(user, res) :
498
xmpp_rosters_find_own_resource(server, res);
499
if (resource == NULL)
502
signal_emit("xmpp presence changed", 4, server, full_jid,
503
XMPP_PRESENCE_UNAVAILABLE, status);
506
user->resources = g_slist_remove(user->resources, resource);
508
server->resources = g_slist_remove(server->resources,
511
cleanup_resource(resource, NULL);
519
xmpp_rosters_init(void)
521
signal_add_last("server disconnected", (SIGNAL_FUNC)sig_cleanup);
522
signal_add_first("xmpp roster update", (SIGNAL_FUNC)sig_update);
523
signal_add_first("xmpp presence update",
524
(SIGNAL_FUNC)sig_presence_update);
525
signal_add_first("xmpp presence error",
526
(SIGNAL_FUNC)sig_presence_error);
527
signal_add_first("xmpp presence unavailable",
528
(SIGNAL_FUNC)sig_presence_unavailable);
530
settings_add_str("xmpp_roster", "roster_default_group", "General");
531
settings_add_str("xmpp_roster", "roster_service_name", "Agents/Transports");
532
settings_add_bool("xmpp_roster", "roster_show_offline", TRUE);
533
settings_add_bool("xmpp_roster", "roster_show_offline_unsuscribed", TRUE);
537
xmpp_rosters_deinit(void)
539
signal_remove("server disconnected", (SIGNAL_FUNC)sig_cleanup);
540
signal_remove("xmpp roster update", (SIGNAL_FUNC)sig_update);
541
signal_remove("xmpp presence update", (SIGNAL_FUNC)sig_presence_update);
542
signal_remove("xmpp presence error", (SIGNAL_FUNC)sig_presence_error);
543
signal_remove("xmpp presence unavailable",
544
(SIGNAL_FUNC)sig_presence_unavailable);