jabberd2  2.2.16
sm/mod_privacy.c
Go to the documentation of this file.
00001 /*
00002  * jabberd - Jabber Open Source Server
00003  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
00004  *                    Ryan Eatmon, Robert Norris
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
00019  */
00020 
00021 #include "sm.h"
00022 
00030 static int ns_PRIVACY = 0;
00031 static int ns_BLOCKING = 0;
00032 
00033 typedef struct zebra_st         *zebra_t;
00034 typedef struct zebra_list_st    *zebra_list_t;
00035 typedef struct zebra_item_st    *zebra_item_t;
00036 
00037 typedef enum {
00038     zebra_NONE,
00039     zebra_JID,
00040     zebra_GROUP,
00041     zebra_S10N
00042 } zebra_item_type_t;
00043 
00044 typedef enum {
00045     block_NONE = 0x00,
00046     block_MESSAGE = 0x01,
00047     block_PRES_IN = 0x02,
00048     block_PRES_OUT = 0x04,
00049     block_IQ = 0x08
00050 } zebra_block_type_t;
00051 
00053 struct zebra_st {
00054     xht             lists;
00055 
00056     zebra_list_t    def;
00057 };
00058 
00059 struct zebra_list_st {
00060     pool_t          p;
00061 
00062     char            *name;
00063 
00064     zebra_item_t    items, last;
00065 };
00066 
00067 struct zebra_item_st {
00068     zebra_item_type_t   type;
00069     
00070     jid_t               jid;
00071 
00072     char                *group;
00073 
00074     int                 to;
00075     int                 from;
00076 
00077     int                 deny;       /* 0 = allow, 1 = deny */
00078 
00079     int                 order;
00080 
00081     zebra_block_type_t  block;
00082 
00083     zebra_item_t        next, prev;
00084 };
00085 
00086 typedef struct privacy_st {
00087     /* currently active list */
00088     zebra_list_t        active;
00089 
00090     /* was blocklist requested */
00091     int                 blocklist;
00092 } *privacy_t;
00093 
00094 /* union for xhash_iter_get to comply with strict-alias rules for gcc3 */
00095 union xhashv
00096 {
00097   void **val;
00098   zebra_list_t *z_val;
00099 };
00100 
00101 static void _privacy_free_z(zebra_t z) {
00102     zebra_list_t zlist;
00103     union xhashv xhv;
00104 
00105     log_debug(ZONE, "freeing zebra ctx");
00106 
00107     if(xhash_iter_first(z->lists))
00108         do {
00109             xhv.z_val = &zlist;
00110             xhash_iter_get(z->lists, NULL, NULL, xhv.val);
00111             pool_free(zlist->p);
00112         } while(xhash_iter_next(z->lists));
00113 
00114     xhash_free(z->lists);
00115     free(z);
00116 }
00117 
00118 static void _privacy_user_free(zebra_t *z) {
00119     if(*z != NULL)
00120         _privacy_free_z(*z);
00121 }
00122 
00123 static int _privacy_user_load(mod_instance_t mi, user_t user) {
00124     module_t mod = mi->mod;
00125     zebra_t z;
00126     os_t os;
00127     os_object_t o;
00128     zebra_list_t zlist;
00129     pool_t p;
00130     zebra_item_t zitem, scan;
00131     char *str;
00132 
00133     log_debug(ZONE, "loading privacy lists for %s", jid_user(user->jid));
00134 
00135     /* free if necessary */
00136     z = user->module_data[mod->index];
00137     if(z != NULL)
00138         _privacy_free_z(z);
00139 
00140     z = (zebra_t) calloc(1, sizeof(struct zebra_st));
00141 
00142     z->lists = xhash_new(101);
00143 
00144     user->module_data[mod->index] = z;
00145 
00146     pool_cleanup(user->p, (void (*))(void *) _privacy_user_free, &(user->module_data[mod->index]));
00147 
00148     /* pull the whole lot */
00149     if(storage_get(user->sm->st, "privacy-items", jid_user(user->jid), NULL, &os) == st_SUCCESS) {
00150         if(os_iter_first(os))
00151             do {
00152                 o = os_iter_object(os);
00153 
00154                 /* list name */
00155                 if(!os_object_get_str(os, o, "list", &str)) {
00156                     log_debug(ZONE, "item with no list field, skipping");
00157                     continue;
00158                 }
00159 
00160                 log_debug(ZONE, "got item for list %s", str);
00161 
00162                 zlist = xhash_get(z->lists, str);
00163 
00164                 /* new list */
00165                 if(zlist == NULL) {
00166                     log_debug(ZONE, "creating list %s", str);
00167 
00168                     p = pool_new();
00169 
00170                     zlist = (zebra_list_t) pmalloco(p, sizeof(struct zebra_list_st));
00171 
00172                     zlist->p = p;
00173                     zlist->name = pstrdup(p, str);
00174 
00175                     xhash_put(z->lists, zlist->name, (void *) zlist);
00176                 }
00177 
00178                 /* new item */
00179                 zitem = (zebra_item_t) pmalloco(zlist->p, sizeof(struct zebra_item_st));
00180 
00181                 /* item type */
00182                 if(os_object_get_str(os, o, "type", &str))
00183                     switch(str[0]) {
00184                         case 'j':
00185                             zitem->type = zebra_JID;
00186                             break;
00187 
00188                         case 'g':
00189                             zitem->type = zebra_GROUP;
00190                             break;
00191 
00192                         case 's':
00193                             zitem->type = zebra_S10N;
00194                             break;
00195                     }
00196 
00197                 /* item value, according to type */
00198                 if(zitem->type != zebra_NONE) {
00199                     if(!os_object_get_str(os, o, "value", &str)) {
00200                         log_debug(ZONE, "no value on non-fall-through item, dropping this item");
00201                         continue;
00202                     }
00203 
00204                     switch(zitem->type) {
00205 
00206                         case zebra_JID:
00207                             zitem->jid = jid_new(str, strlen(str));
00208                             if(zitem->jid == NULL) {
00209                                 log_debug(ZONE, "invalid jid '%s' on item, dropping this item", str);
00210                                 continue;
00211                             }
00212 
00213                             pool_cleanup(zlist->p, (void *) jid_free, zitem->jid);
00214 
00215                             log_debug(ZONE, "jid item with value '%s'", jid_full(zitem->jid));
00216 
00217                             break;
00218 
00219                         case zebra_GROUP:
00220                             zitem->group = pstrdup(zlist->p, str);
00221 
00222                             log_debug(ZONE, "group item with value '%s'", zitem->group);
00223 
00224                             break;
00225 
00226                         case zebra_S10N:
00227                             if(strcmp(str, "to") == 0)
00228                                 zitem->to = 1;
00229                             else if(strcmp(str, "from") == 0)
00230                                 zitem->from = 1;
00231                             else if(strcmp(str, "both") == 0)
00232                                 zitem->to = zitem->from = 1;
00233                             else if(strcmp(str, "none") != 0) {
00234                                 log_debug(ZONE, "invalid value '%s' on s10n item, dropping this item", str);
00235                                 continue;
00236                             }
00237 
00238                             log_debug(ZONE, "s10n item with value '%s' (to %d from %d)", str, zitem->to, zitem->from);
00239 
00240                             break;
00241                             
00242                         case zebra_NONE:
00243                             /* can't get here */
00244                             break;
00245                     }
00246                 }
00247 
00248                 /* action */
00249                 os_object_get_bool(os, o, "deny", &zitem->deny);
00250                 if(zitem->deny) {
00251                     log_debug(ZONE, "deny rule");
00252                 } else {
00253                     log_debug(ZONE, "accept rule");
00254                 }
00255 
00256                 os_object_get_int(os, o, "order", &(zitem->order));
00257                 log_debug(ZONE, "order %d", zitem->order);
00258 
00259                 os_object_get_int(os, o, "block", (int*) &(zitem->block));
00260                 log_debug(ZONE, "block 0x%x", zitem->block);
00261 
00262                 /* insert it */
00263                 for(scan = zlist->items; scan != NULL; scan = scan->next)
00264                     if(zitem->order < scan->order)
00265                         break;
00266                 
00267                 /* we're >= everyone, add us to the end */
00268                 if(scan == NULL) {
00269                     if(zlist->last == NULL)
00270                         zlist->items = zlist->last = zitem;
00271                     else {
00272                         zlist->last->next = zitem;
00273                         zitem->prev = zlist->last;
00274                         zlist->last = zitem;
00275                     }
00276                 }
00277                 
00278                 /* insert just before scan */
00279                 else {
00280                     if(zlist->items == scan) {
00281                         zitem->next = zlist->items;
00282                         zlist->items = zitem;
00283                         scan->prev = zitem;
00284                     } else {
00285                         zitem->next = scan;
00286                         zitem->prev = scan->prev;
00287                         scan->prev->next = zitem;
00288                         scan->prev = zitem;
00289                     }
00290                 }
00291             } while(os_iter_next(os));
00292 
00293         os_free(os);
00294     }
00295 
00296     /* default list */
00297     if(storage_get(user->sm->st, "privacy-default", jid_user(user->jid), NULL, &os) == st_SUCCESS) {
00298         if(os_iter_first(os))
00299             do {
00300                 o = os_iter_object(os);
00301 
00302                 if(os_object_get_str(os, o, "default", &str)) {
00303                     z->def = (zebra_list_t) xhash_get(z->lists, str);
00304                     if(z->def == NULL) {
00305                         log_debug(ZONE, "storage says the default list for %s is %s, but it doesn't exist!", jid_user(user->jid), str);
00306                     } else {
00307                         log_debug(ZONE, "user %s has default list %s", jid_user(user->jid), str);
00308                     }
00309                 }
00310             } while(os_iter_next(os));
00311 
00312         os_free(os);
00313     }
00314 
00315     return 0;
00316 }
00317 
00319 static int _privacy_action(user_t user, zebra_list_t zlist, jid_t jid, pkt_type_t ptype, int in) {
00320     zebra_item_t scan;
00321     int match, i;
00322     item_t ritem;
00323     unsigned char domres[2048];
00324 
00325     log_debug(ZONE, "running match on list %s for %s (packet type 0x%x) (%s)", zlist->name, jid_full(jid), ptype, in ? "incoming" : "outgoing");
00326 
00327     /* loop over the list, trying to find a match */
00328     for(scan = zlist->items; scan != NULL; scan = scan->next) {
00329         match = 0;
00330 
00331         switch(scan->type) {
00332             case zebra_NONE:
00333                 /* fall through, all packets match this */
00334                 match = 1;
00335                 break;
00336 
00337             case zebra_JID:
00338                 sprintf(domres, "%s/%s", jid->domain, jid->resource);
00339  
00340                 /* jid check - match node@dom/res, then node@dom, then dom/resource, then dom */
00341                 if(jid_compare_full(scan->jid, jid) == 0 ||
00342                    strcmp(jid_full(scan->jid), jid_user(jid)) == 0 ||
00343                    strcmp(jid_full(scan->jid), domres) == 0 ||
00344                    strcmp(jid_full(scan->jid), jid->domain) == 0)
00345                     match = 1;
00346 
00347                 break;
00348 
00349             case zebra_GROUP:
00350                 /* roster group check - get the roster item, node@dom/res, then node@dom, then dom */
00351                 ritem = xhash_get(user->roster, jid_full(jid));
00352                 if(ritem == NULL) ritem = xhash_get(user->roster, jid_user(jid));
00353                 if(ritem == NULL) ritem = xhash_get(user->roster, jid->domain);
00354 
00355                 /* got it, do the check */
00356                 if(ritem != NULL)
00357                     for(i = 0; i < ritem->ngroups; i++)
00358                         if(strcmp(scan->group, ritem->groups[i]) == 0)
00359                             match = 1;
00360 
00361                 break;
00362 
00363             case zebra_S10N:
00364                 /* roster item check - get the roster item, node@dom/res, then node@dom, then dom */
00365                 ritem = xhash_get(user->roster, jid_full(jid));
00366                 if(ritem == NULL) ritem = xhash_get(user->roster, jid_user(jid));
00367                 if(ritem == NULL) ritem = xhash_get(user->roster, jid->domain);
00368 
00369                 /* got it, do the check */
00370                 if(ritem != NULL)
00371                     if(scan->to == ritem->to && scan->from == ritem->from)
00372                         match = 1;
00373 
00374                 break;
00375         }
00376 
00377         /* if we matched a rule, we have to do packet block matching */
00378         if(match) {
00379             /* no packet blocking, matching done */
00380             if(scan->block == block_NONE)
00381                 return scan->deny;
00382 
00383             /* incoming checks block_MESSAGE, block_PRES_IN and block_IQ */
00384             if(in) {
00385                 if(ptype & pkt_MESSAGE && scan->block & block_MESSAGE)
00386                     return scan->deny;
00387                 if(ptype & pkt_PRESENCE && scan->block & block_PRES_IN)
00388                     return scan->deny;
00389                 if(ptype & pkt_IQ && scan->block & block_IQ)
00390                     return scan->deny;
00391             } else if((ptype & pkt_PRESENCE && scan->block & block_PRES_OUT && ptype != pkt_PRESENCE_PROBE) ||
00392                       (ptype & pkt_MESSAGE && scan->block & block_MESSAGE)) {
00393                 /* outgoing check, block_PRES_OUT */
00394                 /* XXX and block_MESSAGE for XEP-0191 while it violates XEP-0016 */
00395                 return scan->deny;
00396             }
00397         }
00398     }
00399 
00400     /* didn't match the list, so allow */
00401     return 0;
00402 }
00403 
00405 static mod_ret_t _privacy_in_router(mod_instance_t mi, pkt_t pkt) {
00406     module_t mod = mi->mod;
00407     user_t user;
00408     zebra_t z;
00409     sess_t sess = NULL;
00410     zebra_list_t zlist = NULL;
00411 
00412     /* if its coming to the sm, let it in */
00413     if(pkt->to == NULL || pkt->to->node[0] == '\0')
00414         return mod_PASS;
00415 
00416     /* get the user */
00417     user = user_load(mod->mm->sm, pkt->to);
00418     if(user == NULL) {
00419         log_debug(ZONE, "no user %s, passing packet", jid_user(pkt->to));
00420         return mod_PASS;
00421     }
00422 
00423     /* get our lists */
00424     z = (zebra_t) user->module_data[mod->index];
00425 
00426     /* find a session */
00427     if(*pkt->to->resource != '\0')
00428         sess = sess_match(user, pkt->to->resource);
00429 
00430     /* didn't match a session, so use the top session */
00431     if(sess == NULL)
00432         sess = user->top;
00433 
00434     /* get the active list for the session */
00435     if(sess != NULL && sess->module_data[mod->index] != NULL)
00436         zlist = ((privacy_t) sess->module_data[mod->index])->active;
00437 
00438     /* no active list, so use the default list */
00439     if(zlist == NULL)
00440         zlist = z->def;
00441 
00442     /* no list, so allow everything */
00443     if(zlist == NULL)
00444         return mod_PASS;
00445 
00446     /* figure out the action */
00447     if(_privacy_action(user, zlist, pkt->from, pkt->type, 1) == 0)
00448         return mod_PASS;
00449 
00450     /* deny */
00451     log_debug(ZONE, "denying incoming packet based on privacy policy");
00452 
00453     /* iqs get special treatment */
00454     if(pkt->type == pkt_IQ || pkt->type == pkt_IQ_SET)
00455         return -stanza_err_FEATURE_NOT_IMPLEMENTED;
00456 
00457     /* drop it */
00458     pkt_free(pkt);
00459     return mod_HANDLED;
00460 }
00461 
00463 static mod_ret_t _privacy_out_router(mod_instance_t mi, pkt_t pkt) {
00464     module_t mod = mi->mod;
00465     user_t user;
00466     zebra_t z;
00467     sess_t sess = NULL;
00468     zebra_list_t zlist = NULL;
00469     int err, ns;
00470 
00471     /* if its coming from the sm, let it go */
00472     if(pkt->from == NULL || pkt->from->node[0] == '\0')
00473         return mod_PASS;
00474 
00475     /* get the user */
00476     user = user_load(mod->mm->sm, pkt->from);
00477     if(user == NULL) {
00478         log_debug(ZONE, "no user %s, passing packet", jid_user(pkt->to));
00479         return mod_PASS;
00480     }
00481 
00482     /* get our lists */
00483     z = (zebra_t) user->module_data[mod->index];
00484 
00485     /* find a session */
00486     if(*pkt->from->resource != '\0')
00487         sess = sess_match(user, pkt->from->resource);
00488 
00489     /* get the active list for the session */
00490     if(sess != NULL && sess->module_data[mod->index] != NULL)
00491         zlist = ((privacy_t) sess->module_data[mod->index])->active;
00492 
00493     /* no active list, so use the default list */
00494     if(zlist == NULL)
00495         zlist = z->def;
00496 
00497     /* no list, so allow everything */
00498     if(zlist == NULL)
00499         return mod_PASS;
00500 
00501     /* figure out the action */
00502     if(_privacy_action(user, zlist, pkt->to, pkt->type, 0) == 0)
00503         return mod_PASS;
00504 
00505     /* deny */
00506     log_debug(ZONE, "denying outgoing packet based on privacy policy");
00507 
00508     /* messages get special treatment */
00509     if(pkt->type & pkt_MESSAGE) {
00510         /* hack the XEP-0191 error in */
00511         pkt_error(pkt, stanza_err_NOT_ACCEPTABLE);
00512         err = nad_find_elem(pkt->nad, 1, -1, "error", 1);
00513         ns = nad_add_namespace(pkt->nad, urn_BLOCKING_ERR, NULL);
00514         nad_insert_elem(pkt->nad, err, ns, "blocked", NULL);
00515         pkt_sess(pkt, sess);
00516         return mod_HANDLED;
00517     }
00518 
00519     /* drop it */
00520     pkt_free(pkt);
00521     return mod_HANDLED;
00522 }
00523 
00525 static void _privacy_result_builder(xht zhash, const char *name, void *val, void *arg) {
00526     zebra_list_t zlist = (zebra_list_t) val;
00527     pkt_t pkt = (pkt_t) arg;
00528     int ns, query, list, item;
00529     zebra_item_t zitem;
00530     char order[14];
00531 
00532     ns = nad_find_scoped_namespace(pkt->nad, uri_PRIVACY, NULL);
00533     query = nad_find_elem(pkt->nad, 1, ns, "query", 1);
00534 
00535     list = nad_insert_elem(pkt->nad, query, ns, "list", NULL);
00536     nad_set_attr(pkt->nad, list, -1, "name", zlist->name, 0);
00537 
00538     /* run through the items and build the nad */
00539     for(zitem = zlist->items; zitem != NULL; zitem = zitem->next) {
00540         item = nad_insert_elem(pkt->nad, list, ns, "item", NULL);
00541 
00542         switch(zitem->type) {
00543             case zebra_JID:
00544                 nad_set_attr(pkt->nad, item, -1, "type", "jid", 0);
00545                 nad_set_attr(pkt->nad, item, -1, "value", jid_full(zitem->jid), 0);
00546                 break;
00547 
00548             case zebra_GROUP:
00549                 nad_set_attr(pkt->nad, item, -1, "type", "group", 0);
00550                 nad_set_attr(pkt->nad, item, -1, "value", zitem->group, 0);
00551                 break;
00552 
00553             case zebra_S10N:
00554                 nad_set_attr(pkt->nad, item, -1, "type", "subscription", 0);
00555 
00556                 if(zitem->to == 1 && zitem->from == 1)
00557                     nad_set_attr(pkt->nad, item, -1, "value", "both", 4);
00558                 else if(zitem->to == 1)
00559                     nad_set_attr(pkt->nad, item, -1, "value", "to", 2);
00560                 else if(zitem->from == 1)
00561                     nad_set_attr(pkt->nad, item, -1, "value", "from", 4);
00562                 else
00563                     nad_set_attr(pkt->nad, item, -1, "value", "none", 4);
00564 
00565                 break;
00566 
00567             case zebra_NONE:
00568                 break;
00569         }
00570 
00571         if(zitem->deny)
00572             nad_set_attr(pkt->nad, item, -1, "action", "deny", 4);
00573         else
00574             nad_set_attr(pkt->nad, item, -1, "action", "allow", 5);
00575 
00576         snprintf(order, 14, "%d", zitem->order);
00577         order[13] = '\0';
00578 
00579         nad_set_attr(pkt->nad, item, -1, "order", order, 0);
00580 
00581         if(zitem->block & block_MESSAGE)
00582             nad_insert_elem(pkt->nad, item, ns, "message", NULL);
00583         if(zitem->block & block_PRES_IN)
00584             nad_insert_elem(pkt->nad, item, ns, "presence-in", NULL);
00585         if(zitem->block & block_PRES_OUT)
00586             nad_insert_elem(pkt->nad, item, ns, "presence-out", NULL);
00587         if(zitem->block & block_IQ)
00588             nad_insert_elem(pkt->nad, item, ns, "iq", NULL);
00589     }
00590 }
00591 
00593 static void _privacy_lists_result_builder(const char *name, int namelen, void *val, void *arg) {
00594     zebra_list_t zlist = (zebra_list_t) val;
00595     pkt_t pkt = (pkt_t) arg;
00596     int ns, query, list;
00597 
00598     ns = nad_find_scoped_namespace(pkt->nad, uri_PRIVACY, NULL);
00599     query = nad_find_elem(pkt->nad, 1, ns, "query", 1);
00600 
00601     list = nad_insert_elem(pkt->nad, query, ns, "list", NULL);
00602     nad_set_attr(pkt->nad, list, -1, "name", zlist->name, 0);
00603 }
00604 
00608 static void _unblock_jid(user_t user, storage_t st, zebra_list_t zlist, jid_t jid) {
00609     char filter[1024];
00610     zebra_item_t scan;
00611     sess_t sscan;
00612     jid_t notify_jid = NULL;
00613 
00614     for(scan = zlist->items; scan != NULL; scan = scan->next) {
00615         if(scan->type == zebra_JID && scan->deny && (jid == NULL || jid_compare_full(scan->jid, jid) == 0)) {
00616             if(zlist->items == scan) {
00617                 zlist->items = scan->next;
00618                 if(zlist->items != NULL)
00619                     zlist->items->prev = NULL;
00620             } else {
00621                 assert(scan->prev != NULL);
00622                 scan->prev->next = scan->next;
00623                 if(scan->next != NULL)
00624                     scan->next->prev = scan->prev;
00625             }
00626 
00627             if (zlist->last == scan)
00628                 zlist->last = scan->prev;
00629 
00630             /* and from the storage */
00631             sprintf(filter, "(&(list=%zu:%s)(type=3:jid)(value=%zu:%s))",
00632                     strlen(urn_BLOCKING), urn_BLOCKING, strlen(jid_full(scan->jid)), jid_full(scan->jid));
00633             storage_delete(st, "privacy-items", jid_user(user->jid), filter);
00634 
00635             /* set jid for notify */
00636             notify_jid = scan->jid;
00637         }
00638 
00639         /* update unblocked contact with presence information of all sessions */
00640 
00641         /* XXX NOTE !!! There is a possibility that we notify more than once
00642          * if user edited the privacy list manually, not with XEP-0191.
00643          * Well... We're going to live with it. ;-) */
00644         if(notify_jid != NULL && pres_trust(user, notify_jid))
00645             for(sscan = user->sessions; sscan != NULL; sscan = sscan->next) {
00646                 /* do not update if session is not available,
00647                  * we sent presence direct or got error bounce */
00648                 if(!sscan->available || jid_search(sscan->A, notify_jid) || jid_search(sscan->E, notify_jid))
00649                     continue;
00650     
00651                 log_debug(ZONE, "updating unblocked %s with presence from %s", jid_full(notify_jid), jid_full(sscan->jid));
00652                 pkt_router(pkt_dup(sscan->pres, jid_full(notify_jid), jid_full(sscan->jid)));
00653             }
00654     }
00655 }
00656 
00658 static mod_ret_t _privacy_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) {
00659     module_t mod = mi->mod;
00660     int ns, query, list, name, active, def, item, type, value, action, order, blocking, jid, push = 0;
00661     char corder[14], str[256], filter[1024];
00662     zebra_t z;
00663     zebra_list_t zlist, old;
00664     pool_t p;
00665     zebra_item_t zitem, scan;
00666     sess_t sscan;
00667     jid_t jidt;
00668     pkt_t result;
00669     os_t os;
00670     os_object_t o;
00671     st_ret_t ret;
00672 
00673     /* we only want to play with iq:privacy and urn:xmpp:blocking packets */
00674     if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || (pkt->ns != ns_PRIVACY && pkt->ns != ns_BLOCKING))
00675         return mod_PASS;
00676 
00677     /* if it has a to, throw it out */
00678     if(pkt->to != NULL)
00679         return -stanza_err_BAD_REQUEST;
00680 
00681     /* get our lists */
00682     z = (zebra_t) sess->user->module_data[mod->index];
00683 
00684     /* create session privacy description */
00685     if(sess->module_data[mod->index] == NULL)
00686         sess->module_data[mod->index] = (void *) pmalloco(sess->p, sizeof(struct privacy_st));
00687 
00688     /* handle XEP-0191: Simple Communications Blocking
00689      * as simplified frontend to default privacy list */
00690     if(pkt->ns == ns_BLOCKING) {
00691         if(pkt->type == pkt_IQ_SET) {
00692             /* find out what to do */
00693             int block;
00694             ns = nad_find_scoped_namespace(pkt->nad, urn_BLOCKING, NULL);
00695             blocking = nad_find_elem(pkt->nad, 1, ns, "block", 1);
00696             if(blocking >= 0)
00697                 block = 1;
00698             else {
00699                 blocking = nad_find_elem(pkt->nad, 1, ns, "unblock", 1);
00700                 if(blocking >= 0)
00701                     block = 0;
00702                 else
00703                     return -stanza_err_BAD_REQUEST;
00704             }
00705 
00706             /* if there is no default list, create one */
00707             if(!z->def) {
00708                 /* remove any previous one */
00709                 if((zlist = xhash_get(z->lists, urn_BLOCKING))) {
00710                     pool_free(zlist->p);
00711                     sprintf(filter, "(list=%zu:%s)", strlen(urn_BLOCKING), urn_BLOCKING);
00712                     storage_delete(mod->mm->sm->st, "privacy-items", jid_user(sess->user->jid), filter);
00713                 }
00714 
00715                 /* create new zebra list with name 'urn:xmpp:blocking' */
00716                 p = pool_new();
00717                 zlist = (zebra_list_t) pmalloco(p, sizeof(struct zebra_list_st));
00718                 zlist->p = p;
00719                 zlist->name = pstrdup(p, urn_BLOCKING);
00720                 xhash_put(z->lists, zlist->name, (void *) zlist);
00721                 
00722                 /* make it default */
00723                 z->def = zlist;
00724 
00725                 /* and in the storage */
00726                 os = os_new();
00727                 o = os_object_new(os);
00728                 os_object_put(o, "default", zlist->name, os_type_STRING);
00729                 ret = storage_replace(mod->mm->sm->st, "privacy-default", jid_user(sess->user->jid), NULL, os);
00730                 os_free(os);
00731                 if(ret != st_SUCCESS)
00732                     return -stanza_err_INTERNAL_SERVER_ERROR;
00733 
00734                 log_debug(ZONE, "blocking created '%s' privacy list and set it default", zlist->name);
00735             } else {
00736                 /* use the default one */
00737                 zlist = z->def;
00738             }
00739             /* activate this list */
00740             ((privacy_t) sess->module_data[mod->index])->active = zlist;
00741             log_debug(ZONE, "session '%s' has now active list '%s'", jid_full(sess->jid), zlist->name);
00742 
00743             item = nad_find_elem(pkt->nad, blocking, ns, "item", 1);
00744             if(item < 0) {
00745                 if(block) {
00746                     /* cannot block unknown */
00747                     return -stanza_err_BAD_REQUEST;
00748                 } else {
00749                     /* unblock all */
00750                     _unblock_jid(sess->user, mod->mm->sm->st, zlist, NULL);
00751 
00752                     /* mark to send blocklist push */
00753                     push = 1;
00754                 }
00755             }
00756 
00757             /* loop over the items */
00758             while(item >= 0) {
00759                 /* extract jid */
00760                 jid = nad_find_attr(pkt->nad, item, -1, "jid", 0);
00761                 if(jid < 0)
00762                     return -stanza_err_BAD_REQUEST;
00763 
00764                 jidt = jid_new(NAD_AVAL(pkt->nad, jid), NAD_AVAL_L(pkt->nad, jid));
00765                 if(jidt == NULL)
00766                     return -stanza_err_BAD_REQUEST;
00767 
00768                 /* find blockitem in the list */
00769                 for(scan = zlist->items; scan != NULL; scan = scan->next)
00770                     if(scan->type == zebra_JID && jid_compare_full(scan->jid, jidt) == 0)
00771                         break;
00772 
00773                 /* take action */
00774                 if(block) {
00775                     if(scan != NULL && scan->deny && scan->block == block_NONE) {
00776                             push = 0;
00777                     } else {
00778                         /* first make us unavailable if user is on roster */
00779                         if(pres_trust(sess->user, jidt))
00780                             for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) {
00781                                 /* do not update if session is not available,
00782                                  * we sent presence direct or got error bounce */
00783                                 if(!sscan->available || jid_search(sscan->A, jidt) || jid_search(sscan->E, jidt))
00784                                     continue;
00785                         
00786                                 log_debug(ZONE, "forcing unavailable to %s from %s after block", jid_full(jidt), jid_full(sscan->jid));
00787                                 pkt_router(pkt_create(sess->user->sm, "presence", "unavailable", jid_full(jidt), jid_full(sscan->jid)));
00788                             }
00789 
00790                         /* new item */
00791                         zitem = (zebra_item_t) pmalloco(zlist->p, sizeof(struct zebra_item_st));
00792                         zitem->type = zebra_JID;
00793 
00794                         zitem->jid = jid_new(NAD_AVAL(pkt->nad, jid), NAD_AVAL_L(pkt->nad, jid));
00795                         pool_cleanup(zlist->p, (void *) jid_free, zitem->jid);
00796                         zitem->deny = 1;
00797                         zitem->block = block_NONE;
00798 
00799                         /* insert it in front of list */
00800                         zitem->order = 0;
00801                         if(zlist->last == NULL) {
00802                             zlist->items = zlist->last = zitem;
00803                         } else {
00804                             zitem->next = zlist->items;
00805                             zlist->items->prev = zitem;
00806                             zlist->items = zitem;
00807                         }
00808 
00809                         /* and into the storage backend */
00810                         os = os_new();
00811                         o = os_object_new(os);
00812                         os_object_put(o, "list", zlist->name, os_type_STRING);
00813                         os_object_put(o, "type", "jid", os_type_STRING);
00814                         os_object_put(o, "value", jid_full(zitem->jid), os_type_STRING);
00815                         os_object_put(o, "deny", &zitem->deny, os_type_BOOLEAN);
00816                         os_object_put(o, "order", &zitem->order, os_type_INTEGER);
00817                         os_object_put(o, "block", &zitem->block, os_type_INTEGER);
00818                         ret = storage_put(mod->mm->sm->st, "privacy-items", jid_user(sess->user->jid), os);
00819                         os_free(os);
00820                         if(ret != st_SUCCESS) {
00821                             jid_free(jidt);
00822                             return -stanza_err_INTERNAL_SERVER_ERROR;
00823                         }
00824 
00825                         /* mark to send blocklist push */
00826                         push = 1;
00827                     }
00828                 } else {
00829                     /* unblock action */
00830                     if(scan != NULL && scan->deny) {
00831                         /* remove all jid deny ocurrences from the privacy list */
00832                         _unblock_jid(sess->user, mod->mm->sm->st, zlist, jidt);
00833 
00834                         /* mark to send blocklist push */
00835                         push = 1;
00836                     } else {
00837                         jid_free(jidt);
00838                         return -stanza_err_ITEM_NOT_FOUND;
00839                     }
00840                 }
00841 
00842                 jid_free(jidt);
00843 
00844                 /* next item */
00845                 item = nad_find_elem(pkt->nad, item, ns, "item", 0);
00846             }
00847 
00848             /* return empty result */
00849             result = pkt_create(pkt->sm, "iq", "result", NULL, NULL);
00850             pkt_id(pkt, result);
00851             pkt_sess(result, sess);
00852 
00853             /* blocklist push */
00854             if(push) {
00855                 for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) {
00856                     /* don't push to us or to anyone who hasn't requested blocklist */
00857                     if(sscan == sess || sscan->module_data[mod->index] == NULL || ((privacy_t) sscan->module_data[mod->index])->blocklist == 0)
00858                         continue;
00859 
00860                     result = pkt_dup(pkt, jid_full(sscan->jid), NULL);
00861                     if(result->from != NULL) {
00862                         jid_free(result->from);
00863                         nad_set_attr(result->nad, 1, -1, "from", NULL, 0);
00864                     }
00865                     pkt_id_new(result);
00866                     pkt_sess(result, sscan);
00867                 }
00868             }
00869 
00870             /* and done with request */
00871             pkt_free(pkt);
00872             return mod_HANDLED;
00873         }
00874 
00875         /* it's a get */
00876         ns = nad_find_scoped_namespace(pkt->nad, urn_BLOCKING, NULL);
00877         blocking = nad_find_elem(pkt->nad, 1, ns, "blocklist", 1);
00878         if(blocking < 0)
00879             return -stanza_err_BAD_REQUEST;
00880 
00881         result = pkt_create(pkt->sm, "iq", "result", NULL, NULL);
00882         pkt_id(pkt, result);
00883         ns = nad_add_namespace(result->nad, urn_BLOCKING, NULL);
00884         blocking = nad_insert_elem(result->nad, 1, ns, "blocklist", NULL);
00885 
00886         /* insert items only from the default list */
00887         if(z->def != NULL) {
00888             log_debug(ZONE, "blocking list is '%s'", z->def->name);
00889             zlist = xhash_get(z->lists, z->def->name);
00890             /* run through the items and build the nad */
00891             for(zitem = zlist->items; zitem != NULL; zitem = zitem->next) {
00892                 /* we're interested in items type 'jid' with action 'deny' only */
00893                 if(zitem->type == zebra_JID && zitem->deny) {
00894                     item = nad_insert_elem(result->nad, blocking, -1, "item", NULL);
00895                     nad_set_attr(result->nad, item, -1, "jid", jid_full(zitem->jid), 0);
00896                 }
00897             }
00898 
00899             /* mark that the blocklist was requested */
00900             ((privacy_t) sess->module_data[mod->index])->blocklist = 1;
00901         }
00902 
00903         /* give it to the session */
00904         pkt_sess(result, sess);
00905         pkt_free(pkt);
00906         return mod_HANDLED;
00907     }
00908 
00909     /* else handle XEP-0016: Privacy Lists */
00910 
00911     /* find the query */
00912     ns = nad_find_scoped_namespace(pkt->nad, uri_PRIVACY, NULL);
00913     query = nad_find_elem(pkt->nad, 1, ns, "query", 1);
00914     if(query < 0)
00915         return -stanza_err_BAD_REQUEST;
00916 
00917     /* update lists or set the active list */
00918     if(pkt->type == pkt_IQ_SET) {
00919         /* find out what we're doing */
00920         list = nad_find_elem(pkt->nad, query, ns, "list", 1);
00921         active = nad_find_elem(pkt->nad, query, ns, "active", 1);
00922         def = nad_find_elem(pkt->nad, query, ns, "default", 1);
00923         
00924         /* we need something to do, but we can't do it all at once */
00925         if((list < 0 && active < 0 && def < 0) || (list >= 0 && (active >=0 || def >= 0)))
00926             return -stanza_err_BAD_REQUEST;
00927 
00928         /* loop over any/all lists and store them */
00929         if(list >= 0) {
00930             /* only allowed to change one list at a time */
00931             if(nad_find_elem(pkt->nad, list, ns, "list", 0) >= 0)
00932                 return -stanza_err_BAD_REQUEST;
00933 
00934             /* get the list name */
00935             name = nad_find_attr(pkt->nad, list, -1, "name", NULL);
00936             if(name < 0) {
00937                 log_debug(ZONE, "no list name specified, failing request");
00938                 return -stanza_err_BAD_REQUEST;
00939             }
00940 
00941             snprintf(str, 256, "%.*s", NAD_AVAL_L(pkt->nad, name), NAD_AVAL(pkt->nad, name));
00942             str[255] = '\0';
00943 
00944             log_debug(ZONE, "updating list %s", str);
00945 
00946             /* make a new one */
00947             p = pool_new();
00948 
00949             zlist = (zebra_list_t) pmalloco(p, sizeof(struct zebra_list_st));
00950 
00951             zlist->p = p;
00952             zlist->name = pstrdup(p, str);
00953 
00954             os = os_new();
00955 
00956             /* loop over the items */
00957             item = nad_find_elem(pkt->nad, list, ns, "item", 1);
00958             while(item >= 0) {
00959                 /* extract things */
00960                 type = nad_find_attr(pkt->nad, item, -1, "type", 0);
00961                 value = nad_find_attr(pkt->nad, item, -1, "value", 0);
00962                 action = nad_find_attr(pkt->nad, item, -1, "action", 0);
00963                 order = nad_find_attr(pkt->nad, item, -1, "order", 0);
00964 
00965                 /* sanity */
00966                 if(action < 0 || order < 0 || (type >= 0 && value < 0)) {
00967                     pool_free(p);
00968                     os_free(os);
00969                     return -stanza_err_BAD_REQUEST;
00970                 }
00971 
00972                 /* new item */
00973                 zitem = (zebra_item_t) pmalloco(p, sizeof(struct zebra_item_st));
00974 
00975                 /* have to store it too */
00976                 o = os_object_new(os);
00977                 os_object_put(o, "list", zlist->name, os_type_STRING);
00978 
00979                 /* type & value */
00980                 if(type >= 0) {
00981                     if(NAD_AVAL_L(pkt->nad, type) == 3 && strncmp("jid", NAD_AVAL(pkt->nad, type), 3) == 0) {
00982                         zitem->type = zebra_JID;
00983 
00984                         zitem->jid = jid_new(NAD_AVAL(pkt->nad, value), NAD_AVAL_L(pkt->nad, value));
00985                         if(zitem->jid == NULL) {
00986                             log_debug(ZONE, "invalid jid '%.*s', failing request", NAD_AVAL_L(pkt->nad, value), NAD_AVAL(pkt->nad, value));
00987                             pool_free(p);
00988                             os_free(os);
00989                             return -stanza_err_BAD_REQUEST;
00990                         }
00991 
00992                         pool_cleanup(p, (void *) jid_free, zitem->jid);
00993 
00994                         log_debug(ZONE, "jid item with value '%s'", jid_full(zitem->jid));
00995 
00996                         os_object_put(o, "type", "jid", os_type_STRING);
00997                         os_object_put(o, "value", jid_full(zitem->jid), os_type_STRING);
00998                     }
00999 
01000                     else if(NAD_AVAL_L(pkt->nad, type) == 5 && strncmp("group", NAD_AVAL(pkt->nad, type), 5) == 0) {
01001                         zitem->type = zebra_GROUP;
01002 
01003                         zitem->group = pstrdupx(zlist->p, NAD_AVAL(pkt->nad, value), NAD_AVAL_L(pkt->nad, value));
01004 
01005                         /* !!! check if the group exists */
01006 
01007                         log_debug(ZONE, "group item with value '%s'", zitem->group);
01008 
01009                         os_object_put(o, "type", "group", os_type_STRING);
01010                         os_object_put(o, "value", zitem->group, os_type_STRING);
01011                     }
01012 
01013                     else if(NAD_AVAL_L(pkt->nad, type) == 12 && strncmp("subscription", NAD_AVAL(pkt->nad, type), 12) == 0) {
01014                         zitem->type = zebra_S10N;
01015 
01016                         os_object_put(o, "type", "subscription", os_type_STRING);
01017 
01018                         if(NAD_AVAL_L(pkt->nad, value) == 2 && strncmp("to", NAD_AVAL(pkt->nad, value), 2) == 0) {
01019                             zitem->to = 1;
01020                             os_object_put(o, "value", "to", os_type_STRING);
01021                         } else if(NAD_AVAL_L(pkt->nad, value) == 4 && strncmp("from", NAD_AVAL(pkt->nad, value), 4) == 0) {
01022                             zitem->from = 1;
01023                             os_object_put(o, "value", "from", os_type_STRING);
01024                         } else if(NAD_AVAL_L(pkt->nad, value) == 4 && strncmp("both", NAD_AVAL(pkt->nad, value), 4) == 0) {
01025                             zitem->to = zitem->from = 1;
01026                             os_object_put(o, "value", "both", os_type_STRING);
01027                         } else if(NAD_AVAL_L(pkt->nad, value) == 4 && strncmp("none", NAD_AVAL(pkt->nad, value), 4) == 0)
01028                             os_object_put(o, "value", "none", os_type_STRING);
01029                         else {
01030                             log_debug(ZONE, "invalid value '%.*s' on s10n item, failing request", NAD_AVAL_L(pkt->nad, value), NAD_AVAL(pkt->nad, value));
01031                             pool_free(p);
01032                             os_free(os);
01033                             return -stanza_err_BAD_REQUEST;
01034                         }
01035 
01036                         log_debug(ZONE, "s10n item with value '%.*s' (to %d from %d)", NAD_AVAL_L(pkt->nad, value), NAD_AVAL(pkt->nad, value), zitem->to, zitem->from);
01037                     }
01038                 }
01039 
01040                 /* action */
01041                 if(NAD_AVAL_L(pkt->nad, action) == 4 && strncmp("deny", NAD_AVAL(pkt->nad, action), 4) == 0) {
01042                     zitem->deny = 1;
01043                     log_debug(ZONE, "deny rule");
01044                 } else if(NAD_AVAL_L(pkt->nad, action) == 5 && strncmp("allow", NAD_AVAL(pkt->nad, action), 5) == 0) {
01045                     zitem->deny = 0;
01046                     log_debug(ZONE, "allow rule");
01047                 } else {
01048                     log_debug(ZONE, "unknown action '%.*s', failing request", NAD_AVAL_L(pkt->nad, action), NAD_AVAL(pkt->nad, action));
01049                     pool_free(p);
01050                     os_free(os);
01051                     return -stanza_err_BAD_REQUEST;
01052                 }
01053 
01054                 os_object_put(o, "deny", &zitem->deny, os_type_BOOLEAN);
01055 
01056                 /* order */
01057                 snprintf(corder, 14, "%.*s", NAD_AVAL_L(pkt->nad, order), NAD_AVAL(pkt->nad, order));
01058                 corder[13] = '\0';
01059                 zitem->order = atoi(corder);
01060 
01061                 os_object_put(o, "order", &zitem->order, os_type_INTEGER);
01062 
01063                 /* block types */
01064                 if(nad_find_elem(pkt->nad, item, ns, "message", 1) >= 0)
01065                     zitem->block |= block_MESSAGE;
01066                 if(nad_find_elem(pkt->nad, item, ns, "presence-in", 1) >= 0)
01067                     zitem->block |= block_PRES_IN;
01068                 if(nad_find_elem(pkt->nad, item, ns, "presence-out", 1) >= 0)
01069                     zitem->block |= block_PRES_OUT;
01070                 if(nad_find_elem(pkt->nad, item, ns, "iq", 1) >= 0)
01071                     zitem->block |= block_IQ;
01072 
01073                 /* merge block all */
01074                 if(zitem->block & block_MESSAGE &&
01075                    zitem->block & block_PRES_IN &&
01076                    zitem->block & block_PRES_OUT &&
01077                    zitem->block & block_IQ)
01078                     zitem->block = block_NONE;
01079 
01080                 os_object_put(o, "block", &zitem->block, os_type_INTEGER);
01081 
01082                 /* insert it */
01083                 for(scan = zlist->items; scan != NULL; scan = scan->next)
01084                     if(zitem->order < scan->order)
01085                         break;
01086             
01087                 /* we're >= everyone, add us to the end */
01088                 if(scan == NULL) {
01089                     if(zlist->last == NULL)
01090                         zlist->items = zlist->last = zitem;
01091                     else {
01092                         zlist->last->next = zitem;
01093                         zitem->prev = zlist->last;
01094                         zlist->last = zitem;
01095                     }
01096                 }
01097             
01098                 /* insert just before scan */
01099                 else {
01100                     if(zlist->items == scan) {
01101                         zitem->next = zlist->items;
01102                         zlist->items = zitem;
01103                         scan->prev = zitem;
01104                     } else {
01105                         zitem->next = scan;
01106                         zitem->prev = scan->prev;
01107                         scan->prev->next = zitem;
01108                         scan->prev = zitem;
01109                     }
01110                 }
01111 
01112                 /* next item */
01113                 item = nad_find_elem(pkt->nad, item, ns, "item", 0);
01114             }
01115 
01116             /* write the whole list out */
01117             sprintf(filter, "(list=%zu:%s)", strlen(zlist->name), zlist->name);
01118 
01119             ret = storage_replace(mod->mm->sm->st, "privacy-items", jid_user(sess->user->jid), filter, os);
01120             os_free(os);
01121 
01122             /* failed! */
01123             if(ret != st_SUCCESS) {
01124                 pool_free(zlist->p);
01125                 return -stanza_err_INTERNAL_SERVER_ERROR;
01126             }
01127 
01128             /* old list pointer */
01129             old = xhash_get(z->lists, zlist->name);
01130 
01131             /* removed list */
01132             if(zlist->items == NULL) {
01133                 log_debug(ZONE, "removed list %s", zlist->name);
01134                 xhash_zap(z->lists, zlist->name);
01135                 pool_free(zlist->p);
01136                 if(old != NULL) pool_free(old->p);
01137                 zlist = NULL;
01138             } else {
01139                 log_debug(ZONE, "updated list %s", zlist->name);
01140                 xhash_put(z->lists, zlist->name, (void *) zlist);
01141                 if(old != NULL) pool_free(old->p);
01142             }
01143 
01144             /* if this was a new list, then noone has it active yet */
01145             if(old != NULL) {
01146 
01147                 /* relink */
01148                 log_debug(ZONE, "relinking sessions");
01149 
01150                 /* loop through sessions, relink */
01151                 for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next)
01152                     if(sscan->module_data[mod->index] != NULL && ((privacy_t) sscan->module_data[mod->index])->active == old) {
01153                         ((privacy_t) sscan->module_data[mod->index])->active = zlist;
01154                         log_debug(ZONE, "session '%s' now has active list '%s'", jid_full(sscan->jid), (zlist != NULL) ? zlist->name : "(NONE)");
01155                     }
01156 
01157                 /* default list */
01158                 if(z->def == old) {
01159                     z->def = zlist;
01160 
01161                     if(zlist == NULL) {
01162                         storage_delete(mod->mm->sm->st, "privacy-default", jid_user(sess->user->jid), NULL);
01163                         log_debug(ZONE, "removed default list");
01164                     }
01165 
01166                     else {
01167                         os = os_new();
01168                         o = os_object_new(os);
01169 
01170                         os_object_put(o, "default", zlist->name, os_type_STRING);
01171 
01172                         storage_replace(mod->mm->sm->st, "privacy-default", jid_user(sess->user->jid), NULL, os);
01173 
01174                         os_free(os);
01175 
01176                         log_debug(ZONE, "default list is now '%s'", (zlist != NULL) ? zlist->name : "(NONE)");
01177                     }
01178                 }
01179             }
01180         }
01181 
01182         /* set the active list */
01183         if(active >= 0) {
01184             name = nad_find_attr(pkt->nad, active, -1, "name", NULL);
01185             if(name < 0) {
01186                 /* no name, no active list */
01187                 log_debug(ZONE, "clearing active list for session '%s'", jid_full(sess->jid));
01188                 ((privacy_t) sess->module_data[mod->index])->active = NULL;
01189             }
01190 
01191             else {
01192                 snprintf(str, 256, "%.*s", NAD_AVAL_L(pkt->nad, name), NAD_AVAL(pkt->nad, name));
01193                 str[255] = '\0';
01194 
01195                 zlist = xhash_get(z->lists, str);
01196                 if(zlist == NULL) {
01197                     log_debug(ZONE, "request to make list '%s' active, but there's no such list", str);
01198                     return -stanza_err_ITEM_NOT_FOUND;
01199                 }
01200 
01201                 ((privacy_t) sess->module_data[mod->index])->active = zlist;
01202 
01203                 log_debug(ZONE, "session '%s' now has active list '%s'", jid_full(sess->jid), str);
01204             }
01205         }
01206 
01207         /* set the default list */
01208         if(def >= 0) {
01209             name = nad_find_attr(pkt->nad, def, -1, "name", NULL);
01210             if(name < 0) {
01211                 /* no name, no default list */
01212                 log_debug(ZONE, "clearing default list for '%s'", jid_user(sess->user->jid));
01213                 z->def = NULL;
01214             }
01215 
01216             else {
01217                 snprintf(str, 256, "%.*s", NAD_AVAL_L(pkt->nad, name), NAD_AVAL(pkt->nad, name));
01218                 str[255] = '\0';
01219 
01220                 zlist = xhash_get(z->lists, str);
01221                 if(zlist == NULL) {
01222                     log_debug(ZONE, "request to make list '%s' default, but there's no such list");
01223                     return -stanza_err_ITEM_NOT_FOUND;
01224                 }
01225 
01226                 z->def = zlist;
01227 
01228                 os = os_new();
01229                 o = os_object_new(os);
01230 
01231                 os_object_put(o, "default", zlist->name, os_type_STRING);
01232 
01233                 storage_replace(mod->mm->sm->st, "privacy-default", jid_user(sess->user->jid), NULL, os);
01234 
01235                 os_free(os);
01236 
01237                 log_debug(ZONE, "'%s' now has default list '%s'", jid_user(sess->user->jid), str);
01238             }
01239         }
01240 
01241         /* done, let them know */
01242         result = pkt_create(pkt->sm, "iq", "result", NULL, NULL);
01243 
01244         pkt_id(pkt, result);
01245 
01246         /* done with this */
01247         pkt_free(pkt);
01248 
01249         /* give it to the session */
01250         pkt_sess(result, sess);
01251 
01252         /* all done */
01253         return mod_HANDLED;
01254     }
01255 
01256     /* its a get */
01257 
01258     /* only allowed to request one list, if any */
01259     list = nad_find_elem(pkt->nad, query, ns, "list", 1);
01260     if(list >= 0 && nad_find_elem(pkt->nad, list, ns, "list", 0) >= 0)
01261         return -stanza_err_BAD_REQUEST;
01262 
01263     result = pkt_create(pkt->sm, "iq", "result", NULL, NULL);
01264 
01265     pkt_id(pkt, result);
01266 
01267     ns = nad_add_namespace(result->nad, uri_PRIVACY, NULL);
01268     query = nad_insert_elem(result->nad, 1, ns, "query", NULL);
01269 
01270     /* just do one */
01271     if(list >= 0) {
01272         name = nad_find_attr(pkt->nad, list, -1, "name", NULL);
01273 
01274         zlist = xhash_getx(z->lists, NAD_AVAL(pkt->nad, name), NAD_AVAL_L(pkt->nad, name));
01275         if(zlist == NULL)
01276             return -stanza_err_ITEM_NOT_FOUND;
01277 
01278         _privacy_result_builder(z->lists, zlist->name, (void *) zlist, (void *) result);
01279     }
01280 
01281     else {
01282         /* walk the list hash and add the lists in */
01283         xhash_walk(z->lists, _privacy_lists_result_builder, (void *) result);
01284     }
01285 
01286     /* tell them about current active and default list if they asked for everything */
01287     if(list < 0) {
01288         /* active */
01289         if(((privacy_t) sess->module_data[mod->index])->active != NULL) {
01290             active = nad_insert_elem(result->nad, query, ns, "active", NULL);
01291             nad_set_attr(result->nad, active, -1, "name", ((privacy_t) sess->module_data[mod->index])->active->name, 0);
01292         }
01293 
01294         /* and the default list */
01295         if(z->def != NULL) {
01296             def = nad_insert_elem(result->nad, query, ns, "default", NULL);
01297             nad_set_attr(result->nad, def, -1, "name", z->def->name, 0);
01298         }
01299     }
01300 
01301     /* give it to the session */
01302     pkt_sess(result, sess);
01303 
01304     /* done with this */
01305     pkt_free(pkt);
01306 
01307     /* all done */
01308     return mod_HANDLED;
01309 }
01310 
01311 static void _privacy_user_delete(mod_instance_t mi, jid_t jid) {
01312     log_debug(ZONE, "deleting privacy data for %s", jid_user(jid));
01313 
01314     storage_delete(mi->sm->st, "privacy-items", jid_user(jid), NULL);
01315     storage_delete(mi->sm->st, "privacy-default", jid_user(jid), NULL);
01316 }
01317 
01318 static void _privacy_free(module_t mod) {
01319      sm_unregister_ns(mod->mm->sm, uri_PRIVACY);
01320      feature_unregister(mod->mm->sm, uri_PRIVACY);
01321 }
01322 
01323 DLLEXPORT int module_init(mod_instance_t mi, char *arg) {
01324     module_t mod = mi->mod;
01325 
01326     if (mod->init) return 0;
01327 
01328     mod->user_load = _privacy_user_load;
01329     mod->in_router = _privacy_in_router;
01330     mod->out_router = _privacy_out_router;
01331     mod->in_sess = _privacy_in_sess;
01332     mod->user_delete = _privacy_user_delete;
01333     mod->free = _privacy_free;
01334 
01335     ns_PRIVACY = sm_register_ns(mod->mm->sm, uri_PRIVACY);
01336     feature_register(mod->mm->sm, uri_PRIVACY);
01337     ns_BLOCKING = sm_register_ns(mod->mm->sm, urn_BLOCKING);
01338     feature_register(mod->mm->sm, urn_BLOCKING);
01339 
01340     return 0;
01341 }