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 void _roster_publish_save_item(user_t user, item_t item) { os_t os; os_object_t o; char filter[4096]; int i; log_debug(ZONE, "saving roster item %s for %s", jid_full(item->jid), jid_user(user->jid)); os = os_new(); o = os_object_new(os); os_object_put(o, "jid", jid_full(item->jid), os_type_STRING); if(item->name != NULL) os_object_put(o, "name", item->name, os_type_STRING); os_object_put(o, "to", &item->to, os_type_BOOLEAN); os_object_put(o, "from", &item->from, os_type_BOOLEAN); os_object_put(o, "ask", &item->ask, os_type_INTEGER); snprintf(filter, 4096, "(jid=%s)", jid_full(item->jid)); storage_replace(user->sm->st, "roster-items", jid_user(user->jid), filter, os); os_free(os); snprintf(filter, 4096, "(jid=%s)", jid_full(item->jid)); if(item->ngroups == 0) { storage_delete(user->sm->st, "roster-groups", jid_user(user->jid), filter); return; } os = os_new(); for(i = 0; i < item->ngroups; i++) { o = os_object_new(os); os_object_put(o, "jid", jid_full(item->jid), os_type_STRING); os_object_put(o, "group", item->groups[i], os_type_STRING); } storage_replace(user->sm->st, "roster-groups", jid_user(user->jid), filter, os); os_free(os); }
static int _active_user_create(mod_instance_t mi, jid_t jid) { time_t t; os_t os; os_object_t o; log_debug(ZONE, "activating user %s", jid_user(jid)); t = time(NULL); os = os_new(); o = os_object_new(os); os_object_put_time(o, "time", &t); storage_put(mi->sm->st, "active", jid_user(jid), os); os_free(os); 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 _vacation_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { module_t mod = mi->mod; vacation_t v = sess->user->module_data[mod->index]; int ns, start, end, msg; char dt[30]; pkt_t res; os_t os; os_object_t o; /* we only want to play with vacation iq packets */ if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_VACATION) return mod_PASS; /* if it has a to, throw it out */ if(pkt->to != NULL) return -stanza_err_BAD_REQUEST; /* get */ if(pkt->type == pkt_IQ) { if(v->msg == NULL) { res = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); pkt_id(pkt, res); pkt_free(pkt); pkt_sess(res, sess); return mod_HANDLED; } ns = nad_find_scoped_namespace(pkt->nad, uri_VACATION, NULL); if(v->start != 0) { datetime_out(v->start, dt_DATETIME, dt, 30); nad_insert_elem(pkt->nad, 2, ns, "start", dt); } else nad_insert_elem(pkt->nad, 2, ns, "start", NULL); if(v->end != 0) { datetime_out(v->end, dt_DATETIME, dt, 30); nad_insert_elem(pkt->nad, 2, ns, "end", dt); } else nad_insert_elem(pkt->nad, 2, ns, "end", NULL); nad_insert_elem(pkt->nad, 2, ns, "message", v->msg); pkt_tofrom(pkt); nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); pkt_sess(pkt, sess); return mod_HANDLED; } /* set */ ns = nad_find_scoped_namespace(pkt->nad, uri_VACATION, NULL); start = nad_find_elem(pkt->nad, 2, ns, "start", 1); end = nad_find_elem(pkt->nad, 2, ns, "end", 1); msg = nad_find_elem(pkt->nad, 2, ns, "message", 1); if(start < 0 || end < 0 || msg < 0) { /* forget */ if(v->msg != NULL) { free(v->msg); v->msg = NULL; } v->start = 0; v->end = 0; storage_delete(mi->sm->st, "vacation-settings", jid_user(sess->jid), NULL); res = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); pkt_id(pkt, res); pkt_free(pkt); pkt_sess(res, sess); return mod_HANDLED; } if(NAD_CDATA_L(pkt->nad, start) > 0) { strncpy(dt, NAD_CDATA(pkt->nad, start), (30 < NAD_CDATA_L(pkt->nad, start) ? 30 : NAD_CDATA_L(pkt->nad, start))); v->start = datetime_in(dt); } else v->start = 0; if(NAD_CDATA_L(pkt->nad, end) > 0) { strncpy(dt, NAD_CDATA(pkt->nad, end), (30 < NAD_CDATA_L(pkt->nad, end) ? 30 : NAD_CDATA_L(pkt->nad, end))); v->end = datetime_in(dt); } else v->end = 0; v->msg = (char *) malloc(sizeof(char) * (NAD_CDATA_L(pkt->nad, msg) + 1)); strncpy(v->msg, NAD_CDATA(pkt->nad, msg), NAD_CDATA_L(pkt->nad, msg)); v->msg[NAD_CDATA_L(pkt->nad, msg)] = '\0'; os = os_new(); o = os_object_new(os); os_object_put(o, "start", &v->start, os_type_INTEGER); os_object_put(o, "end", &v->end, os_type_INTEGER); os_object_put(o, "message", v->msg, os_type_STRING); if(storage_replace(mod->mm->sm->st, "vacation-settings", jid_user(sess->user->jid), NULL, os) != st_SUCCESS) { free(v->msg); v->msg = NULL; v->start = 0; v->end = 0; return -stanza_err_INTERNAL_SERVER_ERROR; } res = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); pkt_id(pkt, res); pkt_free(pkt); pkt_sess(res, sess); return mod_HANDLED; }
/** Handles iq messages */ mod_ret_t archive_iq_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { int prefs, type; int section, ptr; os_t os; os_object_t o; char* owner; char buff[2048]; log_debug(ZONE, "In session"); // we only want to play IQs if((!((pkt->type & pkt_IQ) || (pkt->type & pkt_IQ_SET))) || (pkt->ns != ns_ARCHIVE)) return mod_PASS; log_debug(ZONE, "Passed through packet checks"); // if it has a to, throw it out if(pkt->to != NULL) return -stanza_err_BAD_REQUEST; // Who are we? owner=jid_user(sess->jid); // Check for no type or get to send current settings if((type = (nad_find_attr(pkt->nad, 2, -1, "type", NULL)<0)) || ((NAD_AVAL_L(pkt->nad, type ) == 3) && strncmp("get", NAD_AVAL(pkt->nad, type), 3))) { log_debug(ZONE, "Somebody is asking about settings"); send_arch_prefs(mi, sess, pkt); return mod_HANDLED; } // We are setting stuff if(pkt->type == pkt_IQ_SET) { // Prepare to store them log_debug(ZONE, "Setting archiving preferences..."); os = os_new(); if(os == NULL) return mod_PASS; o = os_object_new(os); if(o == NULL) return mod_PASS; // Get rid of old settings storage_delete(pkt->sm->st, tbl_name "_settings", owner, NULL); log_debug(ZONE, "Got rid of old preferences..."); // Find if there is an default option if(!((prefs=nad_find_elem(pkt->nad, 1, -1, "prefs", 1))>0)) return mod_PASS; ptr=nad_find_attr(pkt->nad, prefs, -1, "default", NULL); if(ptr>0) { // Defaults log_debug(ZONE, "Saving defaults..."); os_object_put(o, "jid", owner, os_type_STRING); if (strncmp("roster",NAD_AVAL(pkt->nad, ptr), NAD_AVAL_L(pkt->nad, ptr))==0) prefs=A_ROSTER; else if(strncmp("always",NAD_AVAL(pkt->nad, ptr), NAD_AVAL_L(pkt->nad, ptr))==0) prefs=A_ALWAYS; else prefs=A_NEVER; os_object_put(o, "setting", &prefs, os_type_INTEGER); log_debug(ZONE, "Setting default to %d...", prefs); // What to save always log_debug(ZONE, "Saving what to save always..."); if(((section = nad_find_elem(pkt->nad, prefs, -1, "always", 1))>0)) { log_debug(ZONE, "Found always section %d...", section); prefs=A_ALWAYS; for(ptr = nad_find_elem(pkt->nad, section, -1, "jid", 1); ptr > 0; ptr = nad_find_elem(pkt->nad, ptr, -1, "jid", 0)) { o = os_object_new(os); strncpy(buff, NAD_CDATA(pkt->nad, ptr), min(2047,NAD_CDATA_L(pkt->nad, ptr))); buff[min(2047,NAD_CDATA_L(pkt->nad, ptr))]=0; os_object_put(o, "jid", buff, os_type_STRING); os_object_put(o, "setting", &prefs, os_type_INTEGER); log_debug(ZONE, "Always archiving %s...", buff); } } // What to never save log_debug(ZONE, "Saving what never save..."); if(((section = nad_find_elem(pkt->nad, 2, -1, "never", 1))>0)) { log_debug(ZONE, "Found never section %d...", section); prefs=A_NEVER; for(ptr = nad_find_elem(pkt->nad, section, -1, "jid", 1); ptr > 0; ptr = nad_find_elem(pkt->nad, ptr, -1, "jid", 0)) { o = os_object_new(os); strncpy(buff, NAD_CDATA(pkt->nad, ptr), min(2047,NAD_CDATA_L(pkt->nad, ptr))); buff[min(2047,NAD_CDATA_L(pkt->nad, ptr))]=0; os_object_put(o, "jid", buff, os_type_STRING); os_object_put(o, "setting", &prefs, os_type_INTEGER); log_debug(ZONE, "Never archiving %s...", buff); } } // Save everything storage_put(pkt->sm->st, tbl_name "_settings", owner, os); } // Send current settings send_arch_prefs(mi, sess, pkt); return mod_HANDLED; } return mod_PASS; }
/** * 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; }