jabberd2  2.6.1
mod_roster_publish.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  * Ryan Eatmon, Robert Norris
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 #include "sm.h"
22 
28 #ifndef NO_SM_CACHE
31  time_t time; // when cache was updated
32  time_t active;
33  char *jid_user;
34 };
37  time_t time; // when cache was updated
38  char *groupid;
39  char *groupname;
40 };
41 #endif
42 
43 typedef struct _roster_publish_st {
44  int publish, forcegroups, fixsubs, overridenames, mappedgroups, fixexist;
45  const char *fetchdomain, *fetchuser, *fetchfixed, *dbtable;
46  const char *groupprefix, *groupsuffix, *removedomain;
47  int groupprefixlen, groupsuffixlen;
50 #ifndef NO_SM_CACHE
51  xht active_cache; // cache of values from 'active' storage,
52  // used to check that user exists in sm database
53  xht group_cache; // cache of values from published-roster-groups storage
54  // used to map group id to group name
55 #endif
57 
58 #ifndef NO_SM_CACHE
59 /* free single item of active cache */
60 static void _roster_publish_free_active_cache_walker(const char *key, int keylen, void *val, void *arg) {
61  _roster_publish_active_cache_t item = (_roster_publish_active_cache_t)val;
62  free(item->jid_user);
63  free(item);
64 }
65 /* free single item of group cache */
66 static void _roster_publish_free_group_cache_walker(const char *key, int keylen, void *val, void *arg) {
67  _roster_publish_group_cache_t item = (_roster_publish_group_cache_t)val;
68  free(item->groupid);
69  free(item->groupname);
70  free(item);
71 }
72 #endif
73 
74 /*
75  * get group's descriptive name by it's text id
76  * returned value needs to be freed by caller
77  */
78 static const char *_roster_publish_get_group_name(sm_t sm, roster_publish_t rp, const char *groupid)
79 {
80  os_t os;
81  os_object_t o;
82  char *str;
83  char *group;
84 
85 #ifndef NO_SM_CACHE
86  _roster_publish_group_cache_t group_cached;
87 #endif
88 
89  if(!groupid) return groupid;
90 
91 #ifndef NO_SM_CACHE
92  /* check for remembered group value in cache */
93  if( rp->group_cache_ttl ) {
94  if( rp->group_cache ) {
95  group_cached = xhash_get(rp->group_cache, groupid);
96  if( group_cached != NULL ) {
97  if( (time(NULL) - group_cached->time) >= rp->group_cache_ttl ) {
98  log_debug(ZONE,"group cache: expiring cached value for %s",groupid);
99  xhash_zap(rp->group_cache, groupid);
100  free(group_cached);
101  } else {
102  log_debug(ZONE,"group cache: returning cached value for %s",groupid);
103  return strdup(group_cached->groupname);
104  }
105  }
106  } else {
107  log_debug(ZONE,"group cache: creating cache");
108  rp->group_cache = xhash_new(401);
109  }
110  }
111 #endif
112 
113  if(storage_get(sm->st, "published-roster-groups", groupid, NULL, &os) == st_SUCCESS && os_iter_first(os)) {
114  o = os_iter_object(os);
115  if( os_object_get_str(os, o, "groupname", &str) && str ) {
116  group=strdup(str);
117  } else {
118  group=NULL;
119  }
120  os_free(os);
121 #ifndef NO_SM_CACHE
122  if( rp->group_cache_ttl && group ) {
123  log_debug(ZONE,"group cache: updating cache value for %s",groupid);
124  group_cached = calloc(1, sizeof(struct _roster_publish_group_cache_st));
125  group_cached->time = time(NULL);
126  group_cached->groupid = strdup(groupid);
127  group_cached->groupname = strdup(group);
128  xhash_put(rp->group_cache, group_cached->groupid, group_cached);
129  }
130 #endif
131  return group;
132  } else {
133  return NULL;
134  }
135 }
136 
137 /* free a single roster item */
138 static void _roster_publish_free_walker(xht roster, const char *key, void *val, void *arg)
139 {
140  item_t item = (item_t) val;
141  int i;
142 
143  jid_free(item->jid);
144 
145  if(item->name != NULL)
146  free((void*)item->name);
147 
148  for(i = 0; i < item->ngroups; i++)
149  free((void*)item->groups[i]);
150  free(item->groups);
151 
152  free(item);
153 }
154 
155 static void _roster_publish_save_item(user_t user, item_t item) {
156  os_t os;
157  os_object_t o;
158  char filter[4096];
159  int i;
160 
161  log_debug(ZONE, "saving roster item %s for %s", jid_full(item->jid), jid_user(user->jid));
162 
163  os = os_new();
164  o = os_object_new(os);
165 
166  os_object_put(o, "jid", jid_full(item->jid), os_type_STRING);
167 
168  if(item->name != NULL)
169  os_object_put(o, "name", item->name, os_type_STRING);
170 
171  os_object_put(o, "to", &item->to, os_type_BOOLEAN);
172  os_object_put(o, "from", &item->from, os_type_BOOLEAN);
173  os_object_put(o, "ask", &item->ask, os_type_INTEGER);
174 
175  snprintf(filter, 4096, "(jid=%s)", jid_full(item->jid));
176 
177  storage_replace(user->sm->st, "roster-items", jid_user(user->jid), filter, os);
178 
179  os_free(os);
180 
181  snprintf(filter, 4096, "(jid=%s)", jid_full(item->jid));
182 
183  if(item->ngroups == 0) {
184  storage_delete(user->sm->st, "roster-groups", jid_user(user->jid), filter);
185  return;
186  }
187 
188  os = os_new();
189 
190  for(i = 0; i < item->ngroups; i++) {
191  o = os_object_new(os);
192 
193  os_object_put(o, "jid", jid_full(item->jid), os_type_STRING);
194  os_object_put(o, "group", item->groups[i], os_type_STRING);
195  }
196 
197  storage_replace(user->sm->st, "roster-groups", jid_user(user->jid), filter, os);
198 
199  os_free(os);
200 }
201 
204  roster_publish_t roster_publish = (roster_publish_t) mi->mod->private;
205  os_t os, os_active;
206  os_object_t o, o_active;
207  char *str;
208  const char *group;
209  char filter[4096];
210  const char *fetchkey;
211  int i,j,gpos,found,delete,checksm,tmp_to,tmp_from,tmp_do_change;
212  item_t item;
213  jid_t jid;
214 
215  /* update roster to match published roster */
216  if( roster_publish->publish) {
217  /* free if necessary */
218  if(user->roster == NULL) {
219  log_write(user->sm->log, LOG_NOTICE, "roster_publish: no roster for %s",jid_user(user->jid));
220  return 0;
221  }
222 
223  log_debug(ZONE, "publishing roster for %s",jid_user(user->jid));
224  /* get published roster */
225  if(roster_publish->fetchfixed)
226  fetchkey = roster_publish->fetchfixed;
227  else if(roster_publish->fetchuser)
228  fetchkey = jid_user(user->jid);
229  else if(roster_publish->fetchdomain)
230  fetchkey = user->jid->domain;
231  else
232  fetchkey = "";
233 
234  if( storage_get(user->sm->st, (roster_publish->dbtable ? roster_publish->dbtable : "published-roster"), fetchkey, NULL, &os) == st_SUCCESS ) {
235  if(os_iter_first(os)) {
236  /* iterate on published roster */
237  jid = NULL;
238  do {
239  o = os_iter_object(os);
240  if(os_object_get_str(os, o, "jid", &str)) {
241  int userinsm;
242 #ifndef NO_SM_CACHE
243  _roster_publish_active_cache_t active_cached = 0;
244 #endif
245  log_debug(ZONE, "got %s item for inserting in", str);
246  if( strcmp(str,jid_user(user->jid)) == 0 ) {
247  /* not adding self */
248  continue; /* do { } while( os_iter_next ) */
249  }
250  /* check that published item exists in sm database */
251  checksm=0;
252  if( jid ) jid_free(jid);
253  jid = jid_new(str, -1);
254  if( roster_publish->removedomain ) {
255  if( strcmp("1", roster_publish->removedomain) == 0 || /* XXX HACKY!!! "1" is very config.c dependant */
256  strcmp(jid->domain, roster_publish->removedomain) == 0 ) {
257  checksm = 1;
258  }
259  }
260  if( checksm ) {
261  /* is this a hack? but i want to know was the user activated in sm or no? */
262 #ifndef NO_SM_CACHE
263  /* check for remembered active value in cache */
264  userinsm = -1;
265  if( roster_publish->active_cache_ttl ) {
266  if( roster_publish->active_cache ) {
267  active_cached = xhash_get(roster_publish->active_cache, jid_user(jid));
268  if( active_cached != NULL ) {
269  if( (time(NULL) - active_cached->time) >= roster_publish->active_cache_ttl ) {
270  xhash_zap(roster_publish->active_cache, jid_user(jid));
271  free(active_cached);
272  } else {
273  if( active_cached->active ) {
274  userinsm = 1;
275  } else {
276  userinsm = 0;
277  }
278  }
279  }
280  } else {
281  roster_publish->active_cache = xhash_new(401);
282  }
283  }
284  if( userinsm == -1 ) {
285  if( roster_publish->active_cache_ttl ) {
286  active_cached = calloc(1, sizeof(struct _roster_publish_active_cache_st));
287  active_cached->time = time(NULL);
288  }
289 #endif
290  if(storage_get(user->sm->st, "active", jid_user(jid), NULL, &os_active) == st_SUCCESS
291  && os_iter_first(os_active)) {
292 #ifndef NO_SM_CACHE
293  if( roster_publish->active_cache_ttl ) {
294  o_active = os_iter_object(os_active);
295  os_object_get_time(os_active, o_active, "time", &active_cached->active);
296  }
297 #endif
298  os_free(os_active);
299  userinsm = 1;
300  } else {
301 #ifndef NO_SM_CACHE
302  if( roster_publish->active_cache_ttl ) {
303  active_cached->active = 0;
304  }
305 #endif
306  userinsm = 0;
307  }
308 #ifndef NO_SM_CACHE
309  if( roster_publish->active_cache_ttl ) {
310  active_cached->jid_user = strdup(jid_user(jid));
311  xhash_put(roster_publish->active_cache, active_cached->jid_user, active_cached);
312  }
313  } // if( userinsm == -1 )
314 #endif
315  } else userinsm = 0; // if( checksm )
316  item = xhash_get(user->roster,jid_user(jid));
317  if( item == NULL ) {
318  /* user has no this jid in his roster */
319  /* if we checking sm database and user is not in it, not adding */
320  if( checksm && !userinsm ) {
321  log_debug(ZONE, "published user %s has no record in sm, not adding", jid_user(jid));
322  continue; /* do { } while( os_iter_next ) */
323  }
324  log_debug(ZONE, "user has no %s in roster, adding", jid_user(jid));
325  item = (item_t) calloc(1, sizeof(struct item_st));
326 
327  item->jid = jid_new(jid_user(jid), -1);
328  if(item->jid == NULL) {
329  log_debug(ZONE, "eek! invalid jid %s, skipping it", jid_user(jid));
330  log_write(user->sm->log, LOG_ERR, "roster_publish: eek! invalid jid %s, skipping it", jid_user(jid));
331  /* nvs: is it needed? */
332  free(item);
333  /* nvs: is it needed? */
334  } else {
335  os_object_get_str(os, o, "group", &str);
336  if( roster_publish->mappedgroups ) {
337  group = _roster_publish_get_group_name(user->sm, roster_publish, str); // don't forget to free group
338  } else {
339  if(str)
340  group = strdup(str);
341  else
342  group = NULL;
343  }
344  if( group ) {
345  item->groups = realloc(item->groups, sizeof(char *) * (item->ngroups + 1));
346  item->groups[item->ngroups] = group;
347  item->ngroups++;
348 
349  if(os_object_get_str(os, o, "name", &str))
350  item->name = strdup(str);
351 
352  os_object_get_bool(os, o, "to", &item->to);
353  os_object_get_bool(os, o, "from", &item->from);
354  os_object_get_int(os, o, "ask", &item->ask);
355 
356  log_debug(ZONE, "adding %s to roster from template (to %d from %d ask %d name %s)", jid_full(item->jid), item->to, item->from, item->ask, item->name);
357 
358  /* its good */
359  xhash_put(user->roster, jid_full(item->jid), (void *) item);
360  _roster_publish_save_item(user,item);
361  } else {
362  log_write(user->sm->log, LOG_ERR, "roster_publish: unknown published group id '%s' for %s",str,jid_full(item->jid));
363  free(item);
364  }
365  if (roster_publish->fixexist &&
366  ( (checksm && !userinsm) ||
367  (!checksm && storage_get(user->sm->st, "active", jid_user(jid), NULL, &os_active) == st_SUCCESS && os_iter_first(os_active))
368  )
369  ) {
370  /* Add thise jid to active table*/
371  log_debug(ZONE, "adding published user %s to sm", jid_user(jid));
372  time_t tfe;
373  os_t osfe;
374 
375  os_object_t ofe;
376  tfe = time(NULL);
377  osfe = os_new();
378  ofe = os_object_new(osfe);
379  os_object_put_time(ofe, "time", &tfe);
380  storage_put(mi->sm->st, "active", jid_user(jid), osfe);
381  os_free(osfe);
382  }
383  }
384  }
385  else /* if( item == NULL ) else ... : here item != NULL : user has this jid in his roster */
386  {
387  /* if we checking sm database and user is not in it, remove it from roster */
388  if( checksm && !userinsm ) {
389  log_debug(ZONE, "published user %s has no record in sm, deleting from roster", jid_user(jid));
390  snprintf(filter, 4096, "(jid=%s)", jid_full(jid));
391  storage_delete(user->sm->st, "roster-items", jid_user(user->jid), filter);
392  snprintf(filter, 4096, "(jid=%s)", jid_full(jid));
393  storage_delete(user->sm->st, "roster-groups", jid_user(user->jid), filter);
394 
395  xhash_zap(user->roster, jid_full(jid));
396  _roster_publish_free_walker(NULL, (const char *) jid_full(jid), (void *) item, NULL);
397  continue; /* do { } while( os_iter_next ) */
398  }
399  if( roster_publish->fixsubs ) {
400  /* check subscriptions and correct if needed */
401  os_object_get_bool(os, o, "to", &tmp_to);
402  os_object_get_bool(os, o, "from", &tmp_from);
403  if( item->to != tmp_to || item->from != tmp_from ) {
404  item->to = tmp_to;
405  item->from = tmp_from;
406  log_debug(ZONE, "fixsubs in roster %s, item %s",jid_user(user->jid),jid_user(item->jid));
407  xhash_put(user->roster, jid_full(item->jid), (void *) item);
408  _roster_publish_save_item(user,item);
409  }
410  }
411  if( roster_publish->overridenames ) {
412  /* override display name if it differs */
413  if(os_object_get_str(os, o, "name", &str)) {
414  if( str ) {
415  tmp_do_change = 0;
416  if( ! item->name ) {
417  tmp_do_change = 1;
418  } else {
419  if( strcmp(item->name,str) != 0 ) {
420  tmp_do_change = 1;
421  }
422  }
423  if( tmp_do_change ) {
424  log_debug(ZONE, "replacing name for %s in roster of %s", jid_full(item->jid),jid_user(user->jid));
425  item->name = strdup(str);
426  xhash_put(user->roster, jid_full(item->jid), (void *) item);
427  _roster_publish_save_item(user,item);
428  }
429  } else {
430  log_debug(ZONE,"warning: name is null in published roster for item %s",jid_full(item->jid));
431  }
432  }
433  }
434  if( roster_publish->forcegroups ) {
435  /* item already in roster, check groups if needed */
436  os_object_get_str(os, o, "group", &str);
437  if( roster_publish->mappedgroups ) {
438  group = _roster_publish_get_group_name(user->sm, roster_publish, str); // don't forget to free group
439  if( !group ) {
440  log_write(user->sm->log, LOG_ERR, "roster_publish: unknown published group id '%s' for %s",str, jid_full(item->jid));
441  continue; /* do { } while( os_iter_next ) */
442  }
443  } else {
444  group = strdup(str);
445  }
446  /* find published roster item's group in user's roster */
447  found = 0;
448  for(i = 0; i < item->ngroups; i++) {
449  if( strcmp(item->groups[i],group) == 0 ) {
450  found = 1;
451  /* do not break loop, give groups that matches
452  * prefix and suffix to be deleted
453  */
454  } else {
455  /* check if user's roster group matches
456  * prefix or suffix given in config
457  * and delete such groups (and thus they will be replaced)
458  */
459  delete = 0;
460  if( roster_publish->groupprefix ) {
461  if( strncmp(item->groups[i],roster_publish->groupprefix,roster_publish->groupprefixlen) == 0 ) {
462  delete = 1;
463  }
464  }
465  if( !delete && roster_publish->groupsuffix ) {
466  gpos=strlen(item->groups[i])-roster_publish->groupsuffixlen;
467  if( gpos > 0 ) {
468  if( strcmp(item->groups[i]+gpos,roster_publish->groupsuffix) == 0 ) {
469  delete = 1;
470  }
471  }
472  }
473  /* remove group from roster item */
474  if( delete ) {
475  free((void*)item->groups[i]);
476  for(j = i; j < item->ngroups-1; j++) {
477  item->groups[j]=item->groups[j+1];
478  }
479  item->ngroups--;
480  item->groups = realloc(item->groups, sizeof(char *) * (item->ngroups));
481  }
482  }
483  } /* for(i... */
484  if( !found ) {
485  log_debug(ZONE, "adding group %s to item %s for user %s",group,jid_user(item->jid),jid_user(user->jid));
486  item->groups = realloc(item->groups, sizeof(char *) * (item->ngroups + 1));
487  item->groups[item->ngroups] = group; // will be freed
488  item->ngroups++;
489  /* replace item */
490  xhash_put(user->roster, jid_full(item->jid), (void *) item);
491  _roster_publish_save_item(user,item);
492  } else {
493  free((void*)group);
494  }
495  } /* else if( roster_publish->forcegroups ) */
496  } /* end of if if( item == NULL ) */
497  } /* if( os_object_get(...) */
498  } while(os_iter_next(os));
499  if( jid ) jid_free(jid);
500  }
501  os_free(os);
502  }
503  }
504  return 0;
505 }
506 
507 static void _roster_publish_free(module_t mod) {
508  roster_publish_t roster_publish = (roster_publish_t) mod->private;
509 
510 #ifndef NO_SM_CACHE
511  if( roster_publish->active_cache ) {
513  xhash_free(roster_publish->active_cache);
514  }
515  if( roster_publish->group_cache ) {
517  xhash_free(roster_publish->group_cache);
518  }
519 #endif
520  free(roster_publish);
521 }
522 
523 DLLEXPORT int module_init(mod_instance_t mi, const char *arg) {
524  module_t mod = mi->mod;
525  roster_publish_t roster_publish;
526 
527  if(mod->init) return 0;
528 
529  roster_publish = (roster_publish_t) calloc(1, sizeof(struct _roster_publish_st));
530 
531  if( config_get_one(mod->mm->sm->config, "user.template.publish", 0) ) {
532  roster_publish->publish = 1;
533  roster_publish->fetchdomain = config_get_one(mod->mm->sm->config, "user.template.publish.fetch-key.domain", 0);
534  roster_publish->fetchuser = config_get_one(mod->mm->sm->config, "user.template.publish.fetch-key.user", 0);
535  roster_publish->fetchfixed = config_get_one(mod->mm->sm->config, "user.template.publish.fetch-key.fixed", 0);
536  roster_publish->dbtable = config_get_one(mod->mm->sm->config, "user.template.publish.db-table", 0);
537  roster_publish->removedomain = config_get_one(mod->mm->sm->config, "user.template.publish.check-remove-domain", 0);
538  roster_publish->fixsubs = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.fix-subscriptions", 0), 0);
539  roster_publish->overridenames = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.override-names", 0), 0);
540  roster_publish->mappedgroups = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.mapped-groups.map-groups", 0), 0);
541  roster_publish->fixexist = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.force-create-contacts", 0), 0);
542 #ifndef NO_SM_CACHE
543  roster_publish->active_cache_ttl = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.active-cache-ttl", 0), 0);
544  roster_publish->group_cache_ttl = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.mapped-groups.group-cache-ttl", 0), 0);
545 #endif
546  if( config_get_one(mod->mm->sm->config, "user.template.publish.force-groups", 0) ) {
547  roster_publish->forcegroups = 1;
548  roster_publish->groupprefix = config_get_one(mod->mm->sm->config, "user.template.publish.force-groups.prefix", 0);
549  if( roster_publish->groupprefix ) {
550  roster_publish->groupprefixlen = strlen(roster_publish->groupprefix);
551  }
552  roster_publish->groupsuffix = config_get_one(mod->mm->sm->config, "user.template.publish.force-groups.suffix", 0);
553  if( roster_publish->groupsuffix ) {
554  roster_publish->groupsuffixlen = strlen(roster_publish->groupsuffix);
555  }
556  } else {
557  roster_publish->forcegroups = 0;
558  }
559  } else {
560  roster_publish->publish = 0;
561  }
562  mod->private = roster_publish;
563 
565  mod->free = _roster_publish_free;
566 
567  return 0;
568 }
569 
570 // vim: shiftwidth=4
xht roster
roster for this user (key is full jid of item, value is item_t)
Definition: sm.h:241
static sm_t sm
Definition: main.c:33
data structures and prototypes for the session manager
void xhash_free(xht h)
Definition: xhash.c:241
DLLEXPORT int module_init(mod_instance_t mi, const char *arg)
static int _roster_publish_user_load(mod_instance_t mi, user_t user)
publish the roster from the database
const char * jid_full(jid_t jid)
expand and return the full
Definition: jid.c:346
jid_t jid_new(const char *id, int len)
make a new jid
Definition: jid.c:81
single instance of a module in a chain
Definition: sm.h:446
log_t log
log context
Definition: sm.h:200
config_t config
config context
Definition: sm.h:198
int init
number of times the module intialiser has been called
Definition: sm.h:416
void log_write(log_t log, int level, const char *msgfmt,...)
Definition: log.c:104
int ask
pending subscription (0 == none, 1 == subscribe, 2 == unsubscribe)
Definition: sm.h:161
const char * groupprefix
sm_t sm
sm context
Definition: sm.h:237
int j_atoi(const char *a, int def)
Definition: str.c:87
mm_t mm
module manager
Definition: sm.h:404
static void _roster_publish_free_active_cache_walker(const char *key, int keylen, void *val, void *arg)
static void _roster_publish_save_item(user_t user, item_t item)
#define DLLEXPORT
Definition: c2s.h:47
sm_t sm
sm context
Definition: sm.h:366
static const char * _roster_publish_get_group_name(sm_t sm, roster_publish_t rp, const char *groupid)
module_t mod
module that this is an instance of
Definition: sm.h:449
void * private
module private data
Definition: sm.h:418
storage_t st
storage subsystem
Definition: sm.h:211
session manager global context
Definition: sm.h:167
void jid_free(jid_t jid)
free a jid
Definition: jid.c:286
void xhash_put(xht h, const char *key, void *val)
Definition: xhash.c:163
int ngroups
number of groups in groups array
Definition: sm.h:157
char * domain
Definition: jid.h:45
struct _roster_publish_st * roster_publish_t
Definition: jid.h:42
const char ** groups
groups this item is in
Definition: sm.h:155
void xhash_zap(xht h, const char *key)
Definition: xhash.c:235
#define log_debug(...)
Definition: log.h:65
roster items
Definition: sm.h:150
struct item_st * item_t
roster items
int(* user_load)(mod_instance_t mi, user_t user)
user-load handler
Definition: sm.h:434
static void _roster_publish_free_group_cache_walker(const char *key, int keylen, void *val, void *arg)
void xhash_walk(xht h, xhash_walker w, void *arg)
Definition: xhash.c:268
const char * groupsuffix
int from
subscription to this item (they get presence FROM us, they send presence TO us)
Definition: sm.h:159
jid_t jid
id of this item
Definition: sm.h:151
int to
Definition: sm.h:159
jid_t jid
user jid (user@host)
Definition: sm.h:239
void * xhash_get(xht h, const char *key)
Definition: xhash.c:184
#define ZONE
Definition: mio_impl.h:76
const char * config_get_one(config_t c, const char *key, int num)
get config value n for this key
Definition: config.c:278
void(* free)(module_t mod)
called when module is freed
Definition: sm.h:442
static void _roster_publish_free(module_t mod)
xht xhash_new(int prime)
Definition: xhash.c:96
data for a single module
Definition: sm.h:403
struct _roster_publish_group_cache_st * _roster_publish_group_cache_t
const char * fetchdomain
sm_t sm
sm context
Definition: sm.h:447
struct _roster_publish_active_cache_st * _roster_publish_active_cache_t
const char * removedomain
data for a single user
Definition: sm.h:234
const char * name
display name
Definition: sm.h:153
static void _roster_publish_free_walker(xht roster, const char *key, void *val, void *arg)