void os_copy(os_t src, os_t dst) { os_object_t o,dsto; char *key; void *val, *cval; os_type_t ot; if(os_iter_first(src)) { do { //log_write(log, LOG_ERR, "reading object"); o = os_iter_object(src); dsto = os_object_new(dst); if( os_object_iter_first(o)) { do { os_object_iter_get(o,&key,&val,&ot); switch(ot) { case os_type_BOOLEAN: case os_type_INTEGER: cval = &val; break; default: cval = val; } os_object_put(dsto,key,cval,ot); //log_write(log, LOG_ERR, "wrote."); } while(os_object_iter_next(o)); } } while(os_iter_next(src)); } else { // ! os_iter_first(src) log_debug(ZONE,"os_copy: cannot read source object"); } }
static int _vacation_user_load(mod_instance_t mi, user_t user) { module_t mod = mi->mod; vacation_t v; os_t os; os_object_t o; v = (vacation_t) calloc(1, sizeof(struct _vacation_st)); user->module_data[mod->index] = v; if(storage_get(mod->mm->sm->st, "vacation-settings", jid_user(user->jid), NULL, &os) == st_SUCCESS) { if(os_iter_first(os)) { o = os_iter_object(os); if(os_object_get_time(os, o, "start", &v->start) && os_object_get_time(os, o, "end", &v->end) && os_object_get_str(os, o, "message", &v->msg)) v->msg = strdup(v->msg); else { v->start = 0; v->end = 0; v->msg = NULL; } } os_free(os); } pool_cleanup(user->p, (void (*))(void *) _vacation_user_free, v); return 0; }
static mod_ret_t _iq_private_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { module_t mod = mi->mod; int ns, elem, target, targetns; st_ret_t ret; char filter[4096]; os_t os; os_object_t o; nad_t nad; pkt_t result; sess_t sscan; /* only handle private sets and gets */ if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_PRIVATE) return mod_PASS; /* we're only interested in no to, to our host, or to us */ if(pkt->to != NULL && jid_compare_user(sess->jid, pkt->to) != 0 && strcmp(sess->jid->domain, jid_user(pkt->to)) != 0) return mod_PASS; ns = nad_find_scoped_namespace(pkt->nad, uri_PRIVATE, NULL); elem = nad_find_elem(pkt->nad, 1, ns, "query", 1); /* find the first child */ target = elem + 1; while(target < pkt->nad->ecur) { if(pkt->nad->elems[target].depth > pkt->nad->elems[elem].depth) break; target++; } /* not found, so we're done */ if(target == pkt->nad->ecur) return -stanza_err_BAD_REQUEST; /* find the target namespace */ targetns = NAD_ENS(pkt->nad, target); /* gotta have a namespace */ if(targetns < 0) { log_debug(ZONE, "no namespace specified"); return -stanza_err_BAD_REQUEST; } log_debug(ZONE, "processing private request for %.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); /* get */ if(pkt->type == pkt_IQ) { #ifdef ENABLE_EXPERIMENTAL /* remember that this resource requested the namespace */ if(sess->module_data[mod->index] == NULL) { /* create new hash if necesary */ sess->module_data[mod->index] = xhash_new(101); pool_cleanup(sess->p, (void (*))(void *) xhash_free, sess->module_data[mod->index]); } xhash_put(sess->module_data[mod->index], pstrdupx(sess->p, NAD_NURI(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns)), (void *) 1); #endif snprintf(filter, 4096, "(ns=%i:%.*s)", NAD_NURI_L(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); ret = storage_get(sess->user->sm->st, "private", jid_user(sess->jid), filter, &os); switch(ret) { case st_SUCCESS: if(os_iter_first(os)) { o = os_iter_object(os); if(os_object_get_nad(os, o, "xml", &nad)) { result = pkt_new(sess->user->sm, nad_copy(nad)); if(result != NULL) { nad_set_attr(result->nad, 1, -1, "type", "result", 6); pkt_id(pkt, result); pkt_sess(result, sess); pkt_free(pkt); os_free(os); return mod_HANDLED; } } } os_free(os); /* drop through */ log_debug(ZONE, "storage_get succeeded, but couldn't make packet, faking st_NOTFOUND"); case st_NOTFOUND: log_debug(ZONE, "namespace not found, returning"); /* * !!! really, we should just return a 404. 1.4 just slaps a * result on the packet and sends it back. hurrah for * legacy namespaces. */ nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); pkt_sess(pkt_tofrom(pkt), sess); return mod_HANDLED; case st_FAILED: return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTIMPL: return -stanza_err_FEATURE_NOT_IMPLEMENTED; } } os = os_new(); o = os_object_new(os); snprintf(filter, 4096, "%.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); os_object_put(o, "ns", filter, os_type_STRING); os_object_put(o, "xml", pkt->nad, os_type_NAD); snprintf(filter, 4096, "(ns=%i:%.*s)", NAD_NURI_L(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); ret = storage_replace(sess->user->sm->st, "private", jid_user(sess->jid), filter, os); os_free(os); switch(ret) { case st_FAILED: return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTIMPL: return -stanza_err_FEATURE_NOT_IMPLEMENTED; default: /* create result packet */ result = pkt_create(sess->user->sm, "iq", "result", NULL, NULL); pkt_id(pkt, result); /* and flush it to the session */ pkt_sess(result, sess); #ifdef ENABLE_EXPERIMENTAL /* push it to all resources that read this xmlns item */ snprintf(filter, 4096, "%.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) { /* skip our resource and those that didn't read any private-storage */ if(sscan == sess || sscan->module_data[mod->index] == NULL) continue; /* check whether namespace was read */ if(xhash_get(sscan->module_data[mod->index], filter)) { result = pkt_dup(pkt, jid_full(sscan->jid), NULL); if(result->from != NULL) { jid_free(result->from); nad_set_attr(result->nad, 1, -1, "from", NULL, 0); } pkt_id_new(result); pkt_sess(result, sscan); } } #endif /* finally free the packet */ pkt_free(pkt); return mod_HANDLED; } /* we never get here */ return 0; }
static mod_ret_t _offline_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { st_ret_t ret; os_t os; os_object_t o; nad_t nad; pkt_t queued; int ns, elem, attr; char cttl[15], cstamp[18]; time_t ttl, stamp; /* if they're becoming available for the first time */ if(pkt->type == pkt_PRESENCE && pkt->to == NULL && sess->user->top == NULL) { ret = storage_get(pkt->sm->st, "queue", jid_user(sess->jid), NULL, &os); if(ret != st_SUCCESS) { log_debug(ZONE, "storage_get returned %d", ret); return mod_PASS; } if(os_iter_first(os)) do { o = os_iter_object(os); if(os_object_get_nad(os, o, "xml", &nad)) { queued = pkt_new(pkt->sm, nad_copy(nad)); if(queued == NULL) { log_debug(ZONE, "invalid queued packet, not delivering"); } else { /* check expiry as necessary */ if((ns = nad_find_scoped_namespace(queued->nad, uri_EXPIRE, NULL)) >= 0 && (elem = nad_find_elem(queued->nad, 1, ns, "x", 1)) >= 0 && (attr = nad_find_attr(queued->nad, elem, -1, "seconds", NULL)) >= 0) { snprintf(cttl, 15, "%.*s", NAD_AVAL_L(queued->nad, attr), NAD_AVAL(queued->nad, attr)); ttl = atoi(cttl); /* it should have a x:delay stamp, because we stamp everything we store */ if((ns = nad_find_scoped_namespace(queued->nad, uri_DELAY, NULL)) >= 0 && (elem = nad_find_elem(queued->nad, 1, ns, "x", 1)) >= 0 && (attr = nad_find_attr(queued->nad, elem, -1, "stamp", NULL)) >= 0) { snprintf(cstamp, 18, "%.*s", NAD_AVAL_L(queued->nad, attr), NAD_AVAL(queued->nad, attr)); stamp = datetime_in(cstamp); if(stamp + ttl <= time(NULL)) { log_debug(ZONE, "queued packet has expired, dropping"); pkt_free(queued); continue; } } } log_debug(ZONE, "delivering queued packet to %s", jid_full(sess->jid)); pkt_sess(queued, sess); } } } while(os_iter_next(os)); os_free(os); /* drop the spool */ storage_delete(pkt->sm->st, "queue", jid_user(sess->jid), NULL); } /* pass it so that other modules and mod_presence can get it */ return mod_PASS; }
/* * get group's descriptive name by it's text id * returned value needs to be freed by caller */ static const char *_roster_publish_get_group_name(sm_t sm, roster_publish_t rp, const char *groupid) { os_t os; os_object_t o; char *str; char *group; #ifndef NO_SM_CACHE _roster_publish_group_cache_t group_cached; #endif if(!groupid) return groupid; #ifndef NO_SM_CACHE /* check for remembered group value in cache */ if( rp->group_cache_ttl ) { if( rp->group_cache ) { group_cached = xhash_get(rp->group_cache, groupid); if( group_cached != NULL ) { if( (time(NULL) - group_cached->time) >= rp->group_cache_ttl ) { log_debug(ZONE,"group cache: expiring cached value for %s",groupid); xhash_zap(rp->group_cache, groupid); free(group_cached); } else { log_debug(ZONE,"group cache: returning cached value for %s",groupid); return strdup(group_cached->groupname); } } } else { log_debug(ZONE,"group cache: creating cache"); rp->group_cache = xhash_new(401); } } #endif if(storage_get(sm->st, "published-roster-groups", groupid, NULL, &os) == st_SUCCESS && os_iter_first(os)) { o = os_iter_object(os); if( os_object_get_str(os, o, "groupname", &str) && str ) { group=strdup(str); } else { group=NULL; } os_free(os); #ifndef NO_SM_CACHE if( rp->group_cache_ttl && group ) { log_debug(ZONE,"group cache: updating cache value for %s",groupid); group_cached = calloc(1, sizeof(struct _roster_publish_group_cache_st)); group_cached->time = time(NULL); group_cached->groupid = strdup(groupid); group_cached->groupname = strdup(group); xhash_put(rp->group_cache, group_cached->groupid, group_cached); } #endif return group; } else { return NULL; } }
static int _active_user_load(mod_instance_t mi, user_t user) { os_t os; os_object_t o; /* get their active status */ if(storage_get(user->sm->st, "active", jid_user(user->jid), NULL, &os) == st_SUCCESS && os_iter_first(os)) { o = os_iter_object(os); os_object_get_time(os, o, "time", &user->active); os_free(os); } else /* can't load them if they're inactive */ return 1; return 0; }
/** Send archiving preferences */ void send_arch_prefs(mod_instance_t mi, sess_t sess, pkt_t pkt) { module_t mod = mi->mod; int prefs; int archive=default_mode; int section; int check; char buff[2060]; // 2048 is jid_user maximum length char* ret_str=buff; os_t os = NULL; os_object_t o = NULL; pkt_t reply; // Create a new packet log_debug(ZONE, "Construction of reply with current settings"); reply = pkt_create(sess->user->sm, "iq", "result", NULL, NULL); // Defaults log_debug(ZONE, "Getting defaults"); prefs = nad_append_elem(reply->nad, nad_add_namespace(reply->nad, archive_uri, NULL), "prefs", 2); // Load defaults snprintf(buff, 2060, "(jid=%s)", jid_user(sess->jid)); if((storage_get(sess->user->sm->st, tbl_name "_settings", jid_user(sess->jid), buff, &os) == st_SUCCESS) && (os_iter_first(os)) && ((o=os_iter_object(os))!=NULL)) os_object_get_int(os, o, "setting", &archive); // Set defaults switch(archive) { case A_ALWAYS: nad_set_attr(reply->nad, prefs, -1,"default", "always", 6); break; case A_ROSTER: nad_set_attr(reply->nad, prefs, -1,"default", "roster", 6); break; default: nad_set_attr(reply->nad, prefs, -1,"default", "never", 5); break; } // Cleanup if(o != NULL) { os_object_free(o); o=NULL; } if(os != NULL) { os_free(os); os=NULL; } // Always archiving log_debug(ZONE, "Getting what to archive always"); section = nad_append_elem(reply->nad, -1, "always", 3); if(storage_get(sess->user->sm->st, tbl_name "_settings", jid_user(sess->jid), "(setting=1)", &os) == st_SUCCESS) if(os_iter_first(os)) do { o = os_iter_object(os); if((o != NULL) && (os_object_get_str(os, o, "jid", &ret_str)) && (ret_str != NULL)) { nad_append_elem(reply->nad, -1, "jid", 4); nad_append_cdata(reply->nad, ret_str, strlen(ret_str), 5); } } while(os_iter_next(os)); // Cleanup if(o != NULL) { os_object_free(o); o=NULL; } if(os != NULL) { os_free(os); os=NULL; } // Never archiving log_debug(ZONE, "Getting what to never archive"); section = nad_append_elem(reply->nad, -1, "never", 3); if(storage_get(sess->user->sm->st, tbl_name "_settings", jid_user(sess->jid), "(setting=0)", &os) == st_SUCCESS) if(os_iter_first(os)) do { o = os_iter_object(os); if((o != NULL) && (os_object_get_str(os, o, "jid", &ret_str)) && (ret_str != NULL)) { nad_append_elem(reply->nad, -1, "jid", 4); nad_append_cdata(reply->nad, ret_str, strlen(ret_str), 5); } } while(os_iter_next(os)); // Cleanup if(o != NULL) { os_object_free(o); o=NULL; } if(os != NULL) { os_free(os); os=NULL; } // Send packet pkt_id(pkt, reply); pkt_sess(reply, sess); pkt_free(pkt); }
/** * Saves packet into database. * @param direct Direction of the message - 2 = incomming, 1 = sent */ mod_ret_t savepkt(pkt_t pkt, int direct) { int body=-1, sub=-1, type=-1, arch=-1; char *mem=NULL; const *owner = NULL, *other = NULL; int sz = 0; int archive=default_mode; char filter[2060]; // 2048 is jid_user maximum length time_t t=0; jid_t own_jid, other_jid; os_t os, set_os=NULL; os_object_t o, set_o=NULL; // Is it a message? log_debug(ZONE, "Testing message..."); if ( (pkt->type & pkt_MESSAGE) == 0) return mod_PASS; log_debug(ZONE, "It is a message..."); // 0 element is route, 1st is message, we need subelement of message body = nad_find_elem(pkt->nad, 1, -1, "body", 1); log_debug(ZONE, "Body is at %d", body); sub = nad_find_elem(pkt->nad, 1, -1, "subject", 1); log_debug(ZONE, "Subject is at %d", sub); type = nad_find_attr(pkt->nad, 1, -1, "type", NULL); log_debug(ZONE, "Type %d", type); // Are these parts really interesting? if( ( (body < 0) || (NAD_CDATA_L(pkt->nad, body) < 1) ) && ( (sub < 0) || (NAD_CDATA_L(pkt->nad, sub ) < 1) ) ) return mod_PASS; log_debug(ZONE, "It's meaningful message!", pkt->from); // What direction are we talking about? if (direct == IN_D) { own_jid = pkt->to; other_jid = pkt->from; } else { own_jid = pkt->from; other_jid = pkt->to; } // Get JIDs if(own_jid != NULL) { owner=jid_user(own_jid); } else { return mod_PASS; } if(other_jid != NULL) { other=jid_user(other_jid); } else { return mod_PASS; } // Check settings // Load defaults snprintf(filter, 2060, "(jid=%s)", owner); if((storage_get(pkt->sm->st, tbl_name "_settings", owner, filter, &set_os) == st_SUCCESS) && (os_iter_first(set_os)) && ((set_o=os_iter_object(set_os))!=NULL)) os_object_get_int(set_os, set_o, "setting", &archive); // Cleanup if(set_o != NULL) { os_object_free(set_o); set_o=NULL; } if(set_os != NULL) { os_free(set_os); set_os=NULL; } // Load contact specific snprintf(filter, 2060, "(jid=%s)", other); if((storage_get(pkt->sm->st, tbl_name "_settings", owner, filter, &set_os) == st_SUCCESS) && (os_iter_first(set_os)) && ((set_o=os_iter_object(set_os))!=NULL)) os_object_get_int(set_os, set_o, "setting", &archive); // Cleanup if(set_o != NULL) { os_object_free(set_o); set_o=NULL; } if(set_os != NULL) { os_free(set_os); set_os=NULL; } // Do we need to check roster? if(archive==A_ROSTER) { snprintf(filter, 2060, "(jid=%s)", other); if(storage_get(pkt->sm->st, "roster-items", owner, filter, &set_os) == st_SUCCESS) archive=A_ALWAYS; else archive=A_NEVER; if(set_os != NULL) { os_free(set_os); set_os=NULL; } } // Decide if(archive==A_NEVER) return mod_PASS; // Prepare to store them os = os_new(); if(os == NULL) return mod_PASS; o = os_object_new(os); if(o == NULL) return mod_PASS; // Real storing log_debug(ZONE, "Saving message for %s (other party is %s)", owner, other); // Message // Buffer allocation if(body > 0) { sz = NAD_CDATA_L(pkt->nad, body) / 1024; log_debug(ZONE, "Body size %d", NAD_CDATA_L(pkt->nad, body)); } if(sub > 0) { sz = max(sz, NAD_CDATA_L(pkt->nad, sub) / 1024); log_debug(ZONE, "Subj size %d", NAD_CDATA_L(pkt->nad, sub)); } log_debug(ZONE, "Creating buffer of size %d", sz); mem = (char*)malloc(1024 * (sz+1)); if(mem == NULL) return mod_PASS; log_debug(ZONE, "We got past the buffer allocation."); // JID os_object_put(o, "other_jid", other, os_type_STRING); // Body mem[0]=0; if ( (body > 0) && (NAD_CDATA_L(pkt->nad, body) > 0) ) { strncpy(mem, NAD_CDATA(pkt->nad, body), NAD_CDATA_L(pkt->nad, body)); mem[NAD_CDATA_L(pkt->nad, body)] = 0; } os_object_put(o, "message", mem, os_type_STRING); // Subject mem[0]=0; if ( (sub > 0) && (NAD_CDATA_L(pkt->nad, sub ) > 0) ) { strncpy(mem, NAD_CDATA(pkt->nad, sub), NAD_CDATA_L(pkt->nad, sub)); mem[NAD_CDATA_L(pkt->nad, sub)] = 0; } os_object_put(o, "subject", mem, os_type_STRING); // Type mem[0]=0; if ( (type > 0) && (NAD_AVAL_L(pkt->nad, type ) > 0) ) { strncpy(mem, NAD_AVAL(pkt->nad, type), NAD_AVAL_L(pkt->nad, type)); mem[NAD_AVAL_L(pkt->nad, type)] = 0; } os_object_put(o, "type", mem, os_type_STRING); // To and from resources os_object_put(o, "my_resource", own_jid->resource, os_type_STRING); os_object_put(o, "other_resource", other_jid->resource, os_type_STRING); // Time and direction t=time(NULL); os_object_put(o, "direct", &direct, os_type_INTEGER); os_object_put_time(o, "time", &t); // Message ID if (direct == IN_D) { arch = nad_insert_elem(pkt->nad, 1, -1, "archived", ""); nad_set_attr(pkt->nad,arch,-1,"by",jid_user(own_jid), strlen(jid_user(own_jid))); } set_mid(&(pkt->sm->st), &o, pkt->nad, arch); // Save itself storage_put(pkt->sm->st, tbl_name, owner, os); // Cleanup os_object_free(o); os_free(os); free(mem); log_debug(ZONE, "Saved."); return mod_PASS; }