jabberd2
2.2.16
|
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 #define uri_VCARD "vcard-temp" 00031 static int ns_VCARD = 0; 00032 00033 #define VCARD_MAX_FIELD_SIZE (16384) 00034 00035 typedef struct _mod_iq_vcard_st { 00036 size_t vcard_max_field_size_default; 00037 size_t vcard_max_field_size_avatar; 00038 } *mod_iq_vcard_t; 00039 00050 static const char *_iq_vcard_map[] = { 00051 "FN", "fn", 00052 "N/FAMILY", "n-family", 00053 "N/GIVEN", "n-given", 00054 "N/MIDDLE", "n-middle", 00055 "N/PREFIX", "n-prefix", 00056 "N/SUFFIX", "n-suffix", 00057 "NICKNAME", "nickname", 00058 "PHOTO/TYPE", "photo-type", 00059 "PHOTO/BINVAL", "photo-binval", 00060 "PHOTO/EXTVAL", "photo-extval", 00061 "BDAY", "bday", 00062 "ADR/POBOX", "adr-pobox", 00063 "ADR/EXTADD", "adr-extadd", 00064 "ADR/STREET", "adr-street", 00065 "ADR/LOCALITY", "adr-locality", 00066 "ADR/REGION", "adr-region", 00067 "ADR/PCODE", "adr-pcode", 00068 "ADR/CTRY", "adr-country", 00069 "TEL/NUMBER", "tel", 00070 "EMAIL/USERID", "email", 00071 "JABBERID", "jabberid", 00072 "MAILER", "mailer", 00073 "TZ", "tz", 00074 "GEO/LAT", "geo-lat", 00075 "GEO/LON", "geo-lon", 00076 "TITLE", "title", 00077 "ROLE", "role", 00078 "LOGO/TYPE", "logo-type", 00079 "LOGO/BINVAL", "logo-binval", 00080 "LOGO/EXTVAL", "logo-extval", 00081 "AGENT/EXTVAL", "agent-extval", 00082 "ORG/ORGNAME", "org-orgname", 00083 "ORG/ORGUNIT", "org-orgunit", 00084 "NOTE", "note", 00085 "REV", "rev", 00086 "SORT-STRING", "sort-string", 00087 "SOUND/PHONETIC","sound-phonetic", 00088 "SOUND/BINVAL", "sound-binval", 00089 "SOUND/EXTVAL", "sound-extval", 00090 "UID", "uid", 00091 "URL", "url", 00092 "DESC", "desc", 00093 "KEY/TYPE", "key-type", 00094 "KEY/CRED", "key-cred", 00095 NULL, NULL 00096 }; 00097 00098 static os_t _iq_vcard_to_object(mod_instance_t mi, pkt_t pkt) { 00099 os_t os; 00100 os_object_t o; 00101 int i = 0, elem; 00102 char ekey[10], *cdata; 00103 const char *vkey, *dkey, *vskey; 00104 size_t fieldsize; 00105 mod_iq_vcard_t iq_vcard = (mod_iq_vcard_t) mi->mod->private; 00106 00107 log_debug(ZONE, "building object from packet"); 00108 00109 os = os_new(); 00110 o = os_object_new(os); 00111 00112 while(_iq_vcard_map[i] != NULL) { 00113 vkey = _iq_vcard_map[i]; 00114 dkey = _iq_vcard_map[i + 1]; 00115 00116 i += 2; 00117 00118 if( !strcmp(vkey, "PHOTO/BINVAL") ) { 00119 fieldsize = iq_vcard->vcard_max_field_size_avatar; 00120 } else { 00121 fieldsize = iq_vcard->vcard_max_field_size_default; 00122 } 00123 00124 vskey = strchr(vkey, '/'); 00125 if(vskey == NULL) { 00126 vskey = vkey; 00127 elem = 2; 00128 } else { 00129 sprintf(ekey, "%.*s", (int) (vskey - vkey), vkey); 00130 elem = nad_find_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 2), ekey, 1); 00131 if(elem < 0) 00132 continue; 00133 vskey++; 00134 } 00135 00136 elem = nad_find_elem(pkt->nad, elem, NAD_ENS(pkt->nad, 2), vskey, 1); 00137 if(elem < 0 || NAD_CDATA_L(pkt->nad, elem) == 0) 00138 continue; 00139 00140 log_debug(ZONE, "extracted vcard key %s val '%.*s' for db key %s", vkey, NAD_CDATA_L(pkt->nad, elem), NAD_CDATA(pkt->nad, elem), dkey); 00141 00142 cdata = malloc(fieldsize); 00143 if(cdata) { 00144 snprintf(cdata, fieldsize, "%.*s", NAD_CDATA_L(pkt->nad, elem), NAD_CDATA(pkt->nad, elem)); 00145 cdata[fieldsize-1] = '\0'; 00146 os_object_put(o, dkey, cdata, os_type_STRING); 00147 free(cdata); 00148 } 00149 } 00150 00151 return os; 00152 } 00153 00154 static pkt_t _iq_vcard_to_pkt(sm_t sm, os_t os) { 00155 pkt_t pkt; 00156 os_object_t o; 00157 int i = 0, elem; 00158 char ekey[10], *dval; 00159 const char *vkey, *dkey, *vskey; 00160 00161 log_debug(ZONE, "building packet from object"); 00162 00163 pkt = pkt_create(sm, "iq", "result", NULL, NULL); 00164 nad_append_elem(pkt->nad, nad_add_namespace(pkt->nad, uri_VCARD, NULL), "vCard", 2); 00165 00166 if(!os_iter_first(os)) 00167 return pkt; 00168 o = os_iter_object(os); 00169 00170 while(_iq_vcard_map[i] != NULL) { 00171 vkey = _iq_vcard_map[i]; 00172 dkey = _iq_vcard_map[i + 1]; 00173 00174 i += 2; 00175 00176 if(!os_object_get_str(os, o, dkey, &dval)) 00177 continue; 00178 00179 vskey = strchr(vkey, '/'); 00180 if(vskey == NULL) { 00181 vskey = vkey; 00182 elem = 2; 00183 } else { 00184 sprintf(ekey, "%.*s", (int) (vskey - vkey), vkey); 00185 elem = nad_find_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 2), ekey, 1); 00186 if(elem < 0) 00187 elem = nad_append_elem(pkt->nad, NAD_ENS(pkt->nad, 2), ekey, 3); 00188 vskey++; 00189 } 00190 00191 log_debug(ZONE, "extracted dbkey %s val '%s' for vcard key %s", dkey, dval, vkey); 00192 00193 nad_append_elem(pkt->nad, NAD_ENS(pkt->nad, 2), vskey, pkt->nad->elems[elem].depth + 1); 00194 nad_append_cdata(pkt->nad, dval, strlen(dval), pkt->nad->elems[elem].depth + 2); 00195 } 00196 00197 return pkt; 00198 } 00199 00200 static mod_ret_t _iq_vcard_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { 00201 os_t os; 00202 st_ret_t ret; 00203 pkt_t result; 00204 00205 /* only handle vcard sets and gets that aren't to anyone */ 00206 if(pkt->to != NULL || (pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_VCARD) 00207 return mod_PASS; 00208 00209 /* get */ 00210 if(pkt->type == pkt_IQ) { 00211 if (sm_storage_rate_limit(sess->user->sm, jid_user(sess->jid))) 00212 return -stanza_err_RESOURCE_CONSTRAINT; 00213 00214 ret = storage_get(sess->user->sm->st, "vcard", jid_user(sess->jid), NULL, &os); 00215 switch(ret) { 00216 case st_FAILED: 00217 return -stanza_err_INTERNAL_SERVER_ERROR; 00218 00219 case st_NOTIMPL: 00220 return -stanza_err_FEATURE_NOT_IMPLEMENTED; 00221 00222 case st_NOTFOUND: 00223 nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); 00224 nad_set_attr(pkt->nad, 1, -1, "to", NULL, 0); 00225 nad_set_attr(pkt->nad, 1, -1, "from", NULL, 0); 00226 00227 pkt_sess(pkt, sess); 00228 00229 return mod_HANDLED; 00230 00231 case st_SUCCESS: 00232 result = _iq_vcard_to_pkt(sess->user->sm, os); 00233 os_free(os); 00234 00235 nad_set_attr(result->nad, 1, -1, "type", "result", 6); 00236 pkt_id(pkt, result); 00237 00238 pkt_sess(result, sess); 00239 00240 pkt_free(pkt); 00241 00242 return mod_HANDLED; 00243 } 00244 00245 /* we never get here */ 00246 pkt_free(pkt); 00247 return mod_HANDLED; 00248 } 00249 00250 os = _iq_vcard_to_object(mi, pkt); 00251 00252 if (sm_storage_rate_limit(sess->user->sm, jid_user(sess->jid))) 00253 return -stanza_err_RESOURCE_CONSTRAINT; 00254 00255 ret = storage_replace(sess->user->sm->st, "vcard", jid_user(sess->jid), NULL, os); 00256 os_free(os); 00257 00258 switch(ret) { 00259 case st_FAILED: 00260 return -stanza_err_INTERNAL_SERVER_ERROR; 00261 00262 case st_NOTIMPL: 00263 return -stanza_err_FEATURE_NOT_IMPLEMENTED; 00264 00265 default: 00266 result = pkt_create(sess->user->sm, "iq", "result", NULL, NULL); 00267 00268 pkt_id(pkt, result); 00269 00270 pkt_sess(result, sess); 00271 00272 pkt_free(pkt); 00273 00274 return mod_HANDLED; 00275 } 00276 00277 /* we never get here */ 00278 pkt_free(pkt); 00279 return mod_HANDLED; 00280 } 00281 00282 /* for the special JID of your jabber server bare domain. 00283 * You can have one for every virtual host 00284 * you can populate it using your DBMS frontend 00285 */ 00286 static mod_ret_t _iq_vcard_pkt_sm(mod_instance_t mi, pkt_t pkt) { 00287 os_t os; 00288 st_ret_t ret; 00289 pkt_t result; 00290 00291 /* only handle vcard sets and gets */ 00292 if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_VCARD) 00293 return mod_PASS; 00294 00295 /* error them if they're trying to do a set */ 00296 if(pkt->type == pkt_IQ_SET) 00297 return -stanza_err_FORBIDDEN; 00298 00299 /* a vcard for the server */ 00300 ret = storage_get(mi->sm->st, "vcard", pkt->to->domain, NULL, &os); 00301 switch(ret) { 00302 case st_FAILED: 00303 return -stanza_err_INTERNAL_SERVER_ERROR; 00304 00305 case st_NOTIMPL: 00306 return -stanza_err_FEATURE_NOT_IMPLEMENTED; 00307 00308 case st_NOTFOUND: 00309 return -stanza_err_ITEM_NOT_FOUND; 00310 00311 case st_SUCCESS: 00312 result = _iq_vcard_to_pkt(mi->sm, os); 00313 os_free(os); 00314 00315 result->to = jid_dup(pkt->from); 00316 result->from = jid_dup(pkt->to); 00317 00318 nad_set_attr(result->nad, 1, -1, "to", jid_full(result->to), 0); 00319 nad_set_attr(result->nad, 1, -1, "from", jid_full(result->from), 0); 00320 00321 pkt_id(pkt, result); 00322 00323 pkt_router(result); 00324 00325 pkt_free(pkt); 00326 00327 return mod_HANDLED; 00328 } 00329 00330 /* we never get here */ 00331 pkt_free(pkt); 00332 return mod_HANDLED; 00333 } 00334 00335 static mod_ret_t _iq_vcard_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt) { 00336 os_t os; 00337 st_ret_t ret; 00338 pkt_t result; 00339 00340 /* only handle vcard sets and gets, without resource */ 00341 if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_VCARD || pkt->to->resource[0] !='\0') 00342 return mod_PASS; 00343 00344 /* error them if they're trying to do a set */ 00345 if(pkt->type == pkt_IQ_SET) 00346 return -stanza_err_FORBIDDEN; 00347 00348 if (sm_storage_rate_limit(user->sm, pkt->from)) 00349 return -stanza_err_RESOURCE_CONSTRAINT; 00350 00351 ret = storage_get(user->sm->st, "vcard", jid_user(user->jid), NULL, &os); 00352 switch(ret) { 00353 case st_FAILED: 00354 return -stanza_err_INTERNAL_SERVER_ERROR; 00355 00356 case st_NOTIMPL: 00357 return -stanza_err_FEATURE_NOT_IMPLEMENTED; 00358 00359 case st_NOTFOUND: 00360 return -stanza_err_SERVICE_UNAVAILABLE; 00361 00362 case st_SUCCESS: 00363 result = _iq_vcard_to_pkt(user->sm, os); 00364 os_free(os); 00365 00366 result->to = jid_dup(pkt->from); 00367 result->from = jid_dup(pkt->to); 00368 00369 nad_set_attr(result->nad, 1, -1, "to", jid_full(result->to), 0); 00370 nad_set_attr(result->nad, 1, -1, "from", jid_full(result->from), 0); 00371 00372 pkt_id(pkt, result); 00373 00374 pkt_router(result); 00375 00376 pkt_free(pkt); 00377 00378 return mod_HANDLED; 00379 } 00380 00381 /* we never get here */ 00382 pkt_free(pkt); 00383 return mod_HANDLED; 00384 } 00385 00386 static void _iq_vcard_user_delete(mod_instance_t mi, jid_t jid) { 00387 log_debug(ZONE, "deleting vcard for %s", jid_user(jid)); 00388 00389 storage_delete(mi->sm->st, "vcard", jid_user(jid), NULL); 00390 } 00391 00392 static void _iq_vcard_free(module_t mod) { 00393 sm_unregister_ns(mod->mm->sm, uri_VCARD); 00394 feature_unregister(mod->mm->sm, uri_VCARD); 00395 free(mod->private); 00396 } 00397 00398 DLLEXPORT int module_init(mod_instance_t mi, char *arg) { 00399 module_t mod = mi->mod; 00400 mod_iq_vcard_t iq_vcard; 00401 00402 if(mod->init) return 0; 00403 00404 mod->pkt_sm = _iq_vcard_pkt_sm; 00405 mod->in_sess = _iq_vcard_in_sess; 00406 mod->pkt_user = _iq_vcard_pkt_user; 00407 mod->user_delete = _iq_vcard_user_delete; 00408 mod->free = _iq_vcard_free; 00409 00410 ns_VCARD = sm_register_ns(mod->mm->sm, uri_VCARD); 00411 feature_register(mod->mm->sm, uri_VCARD); 00412 00413 iq_vcard = (mod_iq_vcard_t) calloc(1, sizeof(struct _mod_iq_vcard_st)); 00414 iq_vcard->vcard_max_field_size_default = j_atoi(config_get_one(mod->mm->sm->config, "user.vcard.max-field-size.default", 0), VCARD_MAX_FIELD_SIZE); 00415 iq_vcard->vcard_max_field_size_avatar = j_atoi(config_get_one(mod->mm->sm->config, "user.vcard.max-field-size.avatar", 0), VCARD_MAX_FIELD_SIZE); 00416 mod->private = iq_vcard; 00417 00418 return 0; 00419 }