jabberd2  2.3.6
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 {
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  os_object_get_str(os, o, "groupname", &str);
116  if( str ) {
117  group=strdup(str);
118  } else {
119  group=NULL;
120  }
121  os_free(os);
122 #ifndef NO_SM_CACHE
123  if( rp->group_cache_ttl && group ) {
124  log_debug(ZONE,"group cache: updating cache value for %s",groupid);
125  group_cached = calloc(1, sizeof(struct _roster_publish_group_cache_st));
126  group_cached->time = time(NULL);
127  group_cached->groupid = strdup(groupid);
128  group_cached->groupname = strdup(group);
129  xhash_put(rp->group_cache, group_cached->groupid, group_cached);
130  }
131 #endif
132  return group;
133  } else {
134  return NULL;
135  }
136 }
137 
138 /* free a single roster item */
139 static void _roster_publish_free_walker(xht roster, const char *key, void *val, void *arg)
140 {
141  item_t item = (item_t) val;
142  int i;
143 
144  jid_free(item->jid);
145 
146  if(item->name != NULL)
147  free((void*)item->name);
148 
149  for(i = 0; i < item->ngroups; i++)
150  free((void*)item->groups[i]);
151  free(item->groups);
152 
153  free(item);
154 }
155 
156 static void _roster_publish_save_item(user_t user, item_t item) {
157  os_t os;
158  os_object_t o;
159  char filter[4096];
160  int i;
161 
162  log_debug(ZONE, "saving roster item %s for %s", jid_full(item->jid), jid_user(user->jid));
163 
164  os = os_new();
165  o = os_object_new(os);
166 
167  os_object_put(o, "jid", jid_full(item->jid), os_type_STRING);
168 
169  if(item->name != NULL)
170  os_object_put(o, "name", item->name, os_type_STRING);
171 
172  os_object_put(o, "to", &item->to, os_type_BOOLEAN);
173  os_object_put(o, "from", &item->from, os_type_BOOLEAN);
174  os_object_put(o, "ask", &item->ask, os_type_INTEGER);
175 
176  snprintf(filter, 4096, "(jid=%s)", jid_full(item->jid));
177 
178  storage_replace(user->sm->st, "roster-items", jid_user(user->jid), filter, os);
179 
180  os_free(os);
181 
182  snprintf(filter, 4096, "(jid=%s)", jid_full(item->jid));
183 
184  if(item->ngroups == 0) {
185  storage_delete(user->sm->st, "roster-groups", jid_user(user->jid), filter);
186  return;
187  }
188 
189  os = os_new();
190 
191  for(i = 0; i < item->ngroups; i++) {
192  o = os_object_new(os);
193 
194  os_object_put(o, "jid", jid_full(item->jid), os_type_STRING);
195  os_object_put(o, "group", item->groups[i], os_type_STRING);
196  }
197 
198  storage_replace(user->sm->st, "roster-groups", jid_user(user->jid), filter, os);
199 
200  os_free(os);
201 }
202 
205  roster_publish_t roster_publish = (roster_publish_t) mi->mod->private;
206  os_t os, os_active;
207  os_object_t o, o_active;
208  char *str;
209  const char *group;
210  char filter[4096];
211  const char *fetchkey;
212  int i,j,gpos,found,delete,checksm,tmp_to,tmp_from,tmp_do_change;
213  item_t item;
214  jid_t jid;
215 
216  /* update roster to match published roster */
217  if( roster_publish->publish) {
218  /* free if necessary */
219  if(user->roster == NULL) {
220  log_write(user->sm->log, LOG_NOTICE, "roster_publish: no roster for %s",jid_user(user->jid));
221  return 0;
222  }
223 
224  log_debug(ZONE, "publishing roster for %s",jid_user(user->jid));
225  /* get published roster */
226  if(roster_publish->fetchfixed)
227  fetchkey = roster_publish->fetchfixed;
228  else if(roster_publish->fetchuser)
229  fetchkey = jid_user(user->jid);
230  else if(roster_publish->fetchdomain)
231  fetchkey = user->jid->domain;
232  else
233  fetchkey = "";
234 
235  if( storage_get(user->sm->st, (roster_publish->dbtable ? roster_publish->dbtable : "published-roster"), fetchkey, NULL, &os) == st_SUCCESS ) {
236  if(os_iter_first(os)) {
237  /* iterate on published roster */
238  jid = NULL;
239  do {
240  o = os_iter_object(os);
241  if(os_object_get_str(os, o, "jid", &str)) {
242  int userinsm;
243 #ifndef NO_SM_CACHE
244  _roster_publish_active_cache_t active_cached = 0;
245 #endif
246  log_debug(ZONE, "got %s item for inserting in", str);
247  if( strcmp(str,jid_user(user->jid)) == 0 ) {
248  /* not adding self */
249  continue; /* do { } while( os_iter_next ) */
250  }
251  /* check that published item exists in sm database */
252  checksm=0;
253  if( jid ) jid_free(jid);
254  jid = jid_new(str, -1);
255  if( roster_publish->removedomain ) {
256  if( strcmp("1", roster_publish->removedomain) == 0 || /* XXX HACKY!!! "1" is very config.c dependant */
257  strcmp(jid->domain, roster_publish->removedomain) == 0 ) {
258  checksm = 1;
259  }
260  }
261  if( checksm ) {
262  /* is this a hack? but i want to know was the user activated in sm or no? */
263 #ifndef NO_SM_CACHE
264  /* check for remembered active value in cache */
265  userinsm = -1;
266  if( roster_publish->active_cache_ttl ) {
267  if( roster_publish->active_cache ) {
268  active_cached = xhash_get(roster_publish->active_cache, jid_user(jid));
269  if( active_cached != NULL ) {
270  if( (time(NULL) - active_cached->time) >= roster_publish->active_cache_ttl ) {
271  xhash_zap(roster_publish->active_cache, jid_user(jid));
272  free(active_cached);
273  } else {
274  if( active_cached->active ) {
275  userinsm = 1;
276  } else {
277  userinsm = 0;
278  }
279  }
280  }
281  } else {
282  roster_publish->active_cache = xhash_new(401);
283  }
284  }
285  if( userinsm == -1 ) {
286  if( roster_publish->active_cache_ttl ) {
287  active_cached = calloc(1, sizeof(struct _roster_publish_active_cache_st));
288  active_cached->time = time(NULL);
289  }
290 #endif
291  if(storage_get(user->sm->st, "active", jid_user(jid), NULL, &os_active) == st_SUCCESS
292  && os_iter_first(os_active)) {
293 #ifndef NO_SM_CACHE
294  if( roster_publish->active_cache_ttl ) {
295  o_active = os_iter_object(os_active);
296  os_object_get_time(os_active, o_active, "time", &active_cached->active);
297  }
298 #endif
299  os_free(os_active);
300  userinsm = 1;
301  } else {
302 #ifndef NO_SM_CACHE
303  if( roster_publish->active_cache_ttl ) {
304  active_cached->active = 0;
305  }
306 #endif
307  userinsm = 0;
308  }
309 #ifndef NO_SM_CACHE
310  if( roster_publish->active_cache_ttl ) {
311  active_cached->jid_user = strdup(jid_user(jid));
312  xhash_put(roster_publish->active_cache, active_cached->jid_user, active_cached);
313  }
314  } // if( userinsm == -1 )
315 #endif
316  } else userinsm = 0; // if( checksm )
317  item = xhash_get(user->roster,jid_user(jid));
318  if( item == NULL ) {
319  /* user has no this jid in his roster */
320  /* if we checking sm database and user is not in it, not adding */
321  if( checksm && !userinsm ) {
322  log_debug(ZONE, "published user %s has no record in sm, not adding", jid_user(jid));
323  continue; /* do { } while( os_iter_next ) */
324  }
325  log_debug(ZONE, "user has no %s in roster, adding", jid_user(jid));
326  item = (item_t) calloc(1, sizeof(struct item_st));
327 
328  item->jid = jid_new(jid_user(jid), -1);
329  if(item->jid == NULL) {
330  log_debug(ZONE, "eek! invalid jid %s, skipping it", jid_user(jid));
331  log_write(user->sm->log, LOG_ERR, "roster_publish: eek! invalid jid %s, skipping it", jid_user(jid));
332  /* nvs: is it needed? */
333  free(item);
334  /* nvs: is it needed? */
335  } else {
336  os_object_get_str(os, o, "group", &str);
337  if( roster_publish->mappedgroups ) {
338  group = _roster_publish_get_group_name(user->sm, roster_publish, str); // don't forget to free group
339  } else {
340  if(str)
341  group = strdup(str);
342  else
343  group = NULL;
344  }
345  if( group ) {
346  item->groups = realloc(item->groups, sizeof(char *) * (item->ngroups + 1));
347  item->groups[item->ngroups] = group;
348  item->ngroups++;
349 
350  if(os_object_get_str(os, o, "name", &str))
351  item->name = strdup(str);
352 
353  os_object_get_bool(os, o, "to", &item->to);
354  os_object_get_bool(os, o, "from", &item->from);
355  os_object_get_int(os, o, "ask", &item->ask);
356 
357  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);
358 
359  /* its good */
360  xhash_put(user->roster, jid_full(item->jid), (void *) item);
361  _roster_publish_save_item(user,item);
362  } else {
363  log_write(user->sm->log, LOG_ERR, "roster_publish: unknown published group id '%s' for %s",str,jid_full(item->jid));
364  free(item);
365  }
366  if (roster_publish->fixexist &&
367  ( (checksm && !userinsm) ||
368  (!checksm && storage_get(user->sm->st, "active", jid_user(jid), NULL, &os_active) == st_SUCCESS && os_iter_first(os_active))
369  )
370  ) {
371  /* Add thise jid to active table*/
372  log_debug(ZONE, "adding published user %s to sm", jid_user(jid));
373  time_t tfe;
374  os_t osfe;
375 
376  os_object_t ofe;
377  tfe = time(NULL);
378  osfe = os_new();
379  ofe = os_object_new(osfe);
380  os_object_put_time(ofe, "time", &tfe);
381  storage_put(mi->sm->st, "active", jid_user(jid), osfe);
382  os_free(osfe);
383  }
384  }
385  }
386  else /* if( item == NULL ) else ... : here item != NULL : user has this jid in his roster */
387  {
388  /* if we checking sm database and user is not in it, remove it from roster */
389  if( checksm && !userinsm ) {
390  log_debug(ZONE, "published user %s has no record in sm, deleting from roster", jid_user(jid));
391  snprintf(filter, 4096, "(jid=%s)", jid_full(jid));
392  storage_delete(user->sm->st, "roster-items", jid_user(user->jid), filter);
393  snprintf(filter, 4096, "(jid=%s)", jid_full(jid));
394  storage_delete(user->sm->st, "roster-groups", jid_user(user->jid), filter);
395 
396  xhash_zap(user->roster, jid_full(jid));
397  _roster_publish_free_walker(NULL, (const char *) jid_full(jid), (void *) item, NULL);
398  continue; /* do { } while( os_iter_next ) */
399  }
400  if( roster_publish->fixsubs ) {
401  /* check subscriptions and correct if needed */
402  os_object_get_bool(os, o, "to", &tmp_to);
403  os_object_get_bool(os, o, "from", &tmp_from);
404  if( item->to != tmp_to || item->from != tmp_from ) {
405  item->to = tmp_to;
406  item->from = tmp_from;
407  log_debug(ZONE, "fixsubs in roster %s, item %s",jid_user(user->jid),jid_user(item->jid));
408  xhash_put(user->roster, jid_full(item->jid), (void *) item);
409  _roster_publish_save_item(user,item);
410  }
411  }
412  if( roster_publish->overridenames ) {
413  /* override display name if it differs */
414  if(os_object_get_str(os, o, "name", &str)) {
415  if( str ) {
416  tmp_do_change = 0;
417  if( ! item->name ) {
418  tmp_do_change = 1;
419  } else {
420  if( strcmp(item->name,str) != 0 ) {
421  tmp_do_change = 1;
422  }
423  }
424  if( tmp_do_change ) {
425  log_debug(ZONE, "replacing name for %s in roster of %s", jid_full(item->jid),jid_user(user->jid));
426  item->name = strdup(str);
427  xhash_put(user->roster, jid_full(item->jid), (void *) item);
428  _roster_publish_save_item(user,item);
429  }
430  } else {
431  log_debug(ZONE,"warning: name is null in published roster for item %s",jid_full(item->jid));
432  }
433  }
434  }
435  if( roster_publish->forcegroups ) {
436  /* item already in roster, check groups if needed */
437  os_object_get_str(os, o, "group", &str);
438  if( roster_publish->mappedgroups ) {
439  group = _roster_publish_get_group_name(user->sm, roster_publish, str); // don't forget to free group
440  if( !group ) {
441  log_write(user->sm->log, LOG_ERR, "roster_publish: unknown published group id '%s' for %s",str, jid_full(item->jid));
442  continue; /* do { } while( os_iter_next ) */
443  }
444  } else {
445  group = strdup(str);
446  }
447  /* find published roster item's group in user's roster */
448  found = 0;
449  for(i = 0; i < item->ngroups; i++) {
450  if( strcmp(item->groups[i],group) == 0 ) {
451  found = 1;
452  /* do not break loop, give groups that matches
453  * prefix and suffix to be deleted
454  */
455  } else {
456  /* check if user's roster group matches
457  * prefix or suffix given in config
458  * and delete such groups (and thus they will be replaced)
459  */
460  delete = 0;
461  if( roster_publish->groupprefix ) {
462  if( strncmp(item->groups[i],roster_publish->groupprefix,roster_publish->groupprefixlen) == 0 ) {
463  delete = 1;
464  }
465  }
466  if( !delete && roster_publish->groupsuffix ) {
467  gpos=strlen(item->groups[i])-roster_publish->groupsuffixlen;
468  if( gpos > 0 ) {
469  if( strcmp(item->groups[i]+gpos,roster_publish->groupsuffix) == 0 ) {
470  delete = 1;
471  }
472  }
473  }
474  /* remove group from roster item */
475  if( delete ) {
476  free((void*)item->groups[i]);
477  for(j = i; j < item->ngroups-1; j++) {
478  item->groups[j]=item->groups[j+1];
479  }
480  item->ngroups--;
481  item->groups = realloc(item->groups, sizeof(char *) * (item->ngroups));
482  }
483  }
484  } /* for(i... */
485  if( !found ) {
486  log_debug(ZONE, "adding group %s to item %s for user %s",group,jid_user(item->jid),jid_user(user->jid));
487  item->groups = realloc(item->groups, sizeof(char *) * (item->ngroups + 1));
488  item->groups[item->ngroups] = group; // will be freed
489  item->ngroups++;
490  /* replace item */
491  xhash_put(user->roster, jid_full(item->jid), (void *) item);
492  _roster_publish_save_item(user,item);
493  } else {
494  free((void*)group);
495  }
496  } /* else if( roster_publish->forcegroups ) */
497  } /* end of if if( item == NULL ) */
498  } /* if( os_object_get(...) */
499  } while(os_iter_next(os));
500  if( jid ) jid_free(jid);
501  }
502  os_free(os);
503  }
504  }
505  return 0;
506 }
507 
508 static void _roster_publish_free(module_t mod) {
509  roster_publish_t roster_publish = (roster_publish_t) mod->private;
510 
511 #ifndef NO_SM_CACHE
512  if( roster_publish->active_cache ) {
514  xhash_free(roster_publish->active_cache);
515  }
516  if( roster_publish->group_cache ) {
518  xhash_free(roster_publish->group_cache);
519  }
520 #endif
521  free(roster_publish);
522 }
523 
524 DLLEXPORT int module_init(mod_instance_t mi, const char *arg) {
525  module_t mod = mi->mod;
526  roster_publish_t roster_publish;
527 
528  if(mod->init) return 0;
529 
530  roster_publish = (roster_publish_t) calloc(1, sizeof(struct _roster_publish_st));
531 
532  if( config_get_one(mod->mm->sm->config, "user.template.publish", 0) ) {
533  roster_publish->publish = 1;
534  roster_publish->fetchdomain = config_get_one(mod->mm->sm->config, "user.template.publish.fetch-key.domain", 0);
535  roster_publish->fetchuser = config_get_one(mod->mm->sm->config, "user.template.publish.fetch-key.user", 0);
536  roster_publish->fetchfixed = config_get_one(mod->mm->sm->config, "user.template.publish.fetch-key.fixed", 0);
537  roster_publish->dbtable = config_get_one(mod->mm->sm->config, "user.template.publish.db-table", 0);
538  roster_publish->removedomain = config_get_one(mod->mm->sm->config, "user.template.publish.check-remove-domain", 0);
539  roster_publish->fixsubs = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.fix-subscriptions", 0), 0);
540  roster_publish->overridenames = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.override-names", 0), 0);
541  roster_publish->mappedgroups = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.mapped-groups.map-groups", 0), 0);
542  roster_publish->fixexist = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.force-create-contacts", 0), 0);
543 #ifndef NO_SM_CACHE
544  roster_publish->active_cache_ttl = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.active-cache-ttl", 0), 0);
545  roster_publish->group_cache_ttl = j_atoi(config_get_one(mod->mm->sm->config, "user.template.publish.mapped-groups.group-cache-ttl", 0), 0);
546 #endif
547  if( config_get_one(mod->mm->sm->config, "user.template.publish.force-groups", 0) ) {
548  roster_publish->forcegroups = 1;
549  roster_publish->groupprefix = config_get_one(mod->mm->sm->config, "user.template.publish.force-groups.prefix", 0);
550  if( roster_publish->groupprefix ) {
551  roster_publish->groupprefixlen = strlen(roster_publish->groupprefix);
552  }
553  roster_publish->groupsuffix = config_get_one(mod->mm->sm->config, "user.template.publish.force-groups.suffix", 0);
554  if( roster_publish->groupsuffix ) {
555  roster_publish->groupsuffixlen = strlen(roster_publish->groupsuffix);
556  }
557  } else {
558  roster_publish->forcegroups = 0;
559  }
560  } else {
561  roster_publish->publish = 0;
562  }
563  mod->private = roster_publish;
564 
566  mod->free = _roster_publish_free;
567 
568  return 0;
569 }
570 
571 // 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)
const char * jid_user(jid_t jid)
expand and return the user
Definition: jid.c:339
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:347
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:277
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)