123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546 |
- /* offline presence authorization "requests" e.g. storing
- * watcher information for offline presentities */
- #include <stdio.h>
- #include "../../str.h"
- #include "../../dprint.h"
- #include "../../mem/mem.h"
- #include "dlist.h"
- #include "presentity.h"
- #include "watcher.h"
- #include "pdomain.h"
- #include "pa_mod.h"
- #include "../../parser/parse_from.h"
- #include <libxml/parser.h>
- #include <libxml/xpath.h>
- #include <presence/pidf.h>
- #include <cds/logger.h>
- #include <time.h>
- #include "offline_winfo.h"
- #include "winfo_doc.h"
- #include "message.h"
- /* ----- Helper and internal functions ----- */
- #define add_str_len(len,p) if (p) if (p->s) len += p->len
- #define set_member_str(buf,len,dst,src) if (src) if (src->s) { \
- memcpy(buf + len, src->s, src->len); \
- dst.s = buf + len; \
- dst.len = src->len; \
- len += src->len; \
- }
- #define string_val(v,s) (v).type = DB_STR; \
- (v).val.str_val=s; \
- (v).nul=(s.len == 0);
- #define time_val(v,t) (v).type = DB_DATETIME; \
- (v).val.time_val=t;\
- (v).nul=0;
- #define get_str_val(rvi,dst) do{if(!rvi.nul){dst.s=(char*)rvi.val.string_val;dst.len=strlen(dst.s);}}while(0)
- #define get_blob_val(rvi,dst) do{if(!rvi.nul){dst=rvi.val.blob_val;}else dst.len=0;}while(0)
- #define get_time_val(rvi,dst) do{if(!rvi.nul){dst=rvi.val.time_val;}}while(0)
- #define get_int_val(rvi,dst) do{if(!rvi.nul){dst=rvi.val.int_val;}else dst=0;}while(0)
- /* expiration time in secs */
- int offline_winfo_expiration = 259200;
- /* status of last subscription */
- static watcher_status_t last_subscription_status = WS_PENDING;
- void set_last_subscription_status(watcher_status_t status)
- {
- last_subscription_status = status;
- }
- watcher_status_t get_last_subscription_status()
- {
- return last_subscription_status;
- }
- static offline_winfo_t *create_winfo(str *uid,
- str *wuri,
- str *events,
- str *domain,
- str *status)
- {
- int len = 0;
- offline_winfo_t *info;
-
- add_str_len(len, uid);
- add_str_len(len, wuri);
- add_str_len(len, events);
- add_str_len(len, domain);
- add_str_len(len, status);
- len += sizeof(offline_winfo_t);
-
- info = (offline_winfo_t*)mem_alloc(len);
- if (info) {
- memset(info, 0, len);
- len = 0;
- set_member_str(info->buffer, len, info->uid, uid);
- set_member_str(info->buffer, len, info->watcher, wuri);
- set_member_str(info->buffer, len, info->events, events);
- set_member_str(info->buffer, len, info->domain, domain);
- set_member_str(info->buffer, len, info->status, status);
- info->created = time(NULL);
- info->expires = info->created + offline_winfo_expiration;
- info->index = -1;
- }
- return info;
- }
- static inline void free_winfo(offline_winfo_t *info)
- {
- if (info) mem_free(info);
- }
- static inline void free_winfos(offline_winfo_t *info)
- {
- offline_winfo_t *n;
-
- while (info) {
- n = info->next;
- free_winfo(info);
- info = n;
- }
- }
- static int db_store_winfo(offline_winfo_t *info)
- {
- /* ignore duplicit records (should be stored only once!) */
- db_key_t cols[20];
- db_val_t vals[20];
- int n = -1;
-
- if (!pa_db) {
- ERR("database not initialized: set parameter \'use_offline_winfo\' to 1\n");
- return -1;
- }
-
- if (pa_dbf.use_table(pa_db, offline_winfo_table) < 0) {
- LOG(L_ERR, "db_add_watcher: Error in use_table\n");
- return -1;
- }
-
- cols[++n] = col_uid;
- string_val(vals[n], info->uid);
-
- cols[++n] = col_watcher;
- string_val(vals[n], info->watcher);
-
- cols[++n] = col_events;
- string_val(vals[n], info->events);
-
- cols[++n] = col_domain;
- string_val(vals[n], info->domain);
-
- cols[++n] = col_status;
- string_val(vals[n], info->status);
-
- cols[++n] = col_created_on;
- time_val(vals[n], info->created);
-
- cols[++n] = col_expires_on;
- time_val(vals[n], info->expires);
- /* index ("dbid") is created automaticaly ! */
-
- /* insert new record into database */
- if (pa_dbf.insert(pa_db, cols, vals, n + 1) < 0) {
- return -1;
- }
- return 0;
- }
- static int get_watcher_uri(struct sip_msg* _m, str* uri)
- {
- struct sip_uri puri;
- int res = 0;
-
- uri->s = get_from(_m)->uri.s;
- uri->len = get_from(_m)->uri.len;
- if (parse_uri(uri->s, uri->len, &puri) < 0) {
- LOG(L_ERR, "Error while parsing URI\n");
- return -1;
- }
- #if 0
- uri->s = puri.user.s;
- if ((!uri->s) || (puri.user.len < 1)) {
- uri->s = puri.host.s;
- uri->len = puri.host.len;
- res = 1; /* it is uri without username ! */
- }
- #endif
- uri->len = puri.host.s + puri.host.len - uri->s;
- return res;
- }
- static int get_events(struct sip_msg* _m, str* events)
- {
- char *c;
- str_clear(events);
-
- if (parse_headers(_m, HDR_EVENT_F, 0) == -1) {
- ERR("Error while parsing headers\n");
- return -1;
- }
- if (_m->event) {
- /* parse_event(_m->event); */
- *events = _m->event->body;
- c = str_strchr(events, ';');
- if (c) events->len = c - events->s;
- }
- return 0;
- }
- int remove_expired_winfos()
- {
- db_key_t keys[] = { col_expires_on };
- db_val_t vals[1] = {
- { DB_DATETIME, 0, { .time_val = time(NULL) } }
- };
- db_op_t ops[] = { OP_LEQ };
- int res = 0;
- if (!pa_db) {
- ERR("database not initialized: set parameter \'use_offline_winfo\' to 1\n");
- return -1;
- }
-
- if (pa_dbf.use_table(pa_db, offline_winfo_table) < 0) {
- LOG(L_ERR, "db_add_watcher: Error in use_table\n");
- return -1;
- }
- res = pa_dbf.delete(pa_db, keys, ops, vals, 1);
- if (res < 0 )
- DBG("ERROR cleaning expired offline winfo\n");
- return res;
- }
- int db_remove_winfos(offline_winfo_t *info)
- {
- db_key_t keys[] = { col_dbid };
- db_val_t vals[1];
- db_op_t ops[] = { OP_EQ };
- int res = 0;
- if (!pa_db) {
- ERR("database not initialized: set parameter \'use_offline_winfo\' to 1\n");
- return -1;
- }
-
- if (pa_dbf.use_table(pa_db, offline_winfo_table) < 0) {
- LOG(L_ERR, "Error in use_table\n");
- return -1;
- }
- while (info) {
- vals[0].type = DB_INT;
- vals[0].nul = 0;
- vals[0].val.int_val = info->index;
- res = pa_dbf.delete(pa_db, keys, ops, vals, 1);
- if (res < 0 )
- DBG("ERROR cleaning expired offline winfo\n");
- info = info->next;
- }
- return res;
- }
- static void send_winfo_cb(struct cell* t, int type, struct tmcb_params* params)
- {
- offline_winfo_t *info = NULL;
- if (!params) {
- ERR("BUG: empty arg\n");
- return;
- }
- if (params->param) info = (offline_winfo_t *)*(params->param);
- if (!info) {
- ERR("BUG: empty arg\n");
- return;
- }
- if ((params->code >= 200) && (params->code < 300)) {
- /* delete infos from DB */
- db_remove_winfos(info);
- }
- else
- ERR("%d response on winfo NOTIFY\n", params->code);
-
- /* delete infos from memory */
- free_winfos(info);
- }
- static int send_winfo(presentity_t *p, offline_winfo_t *info)
- {
- watcher_t *w;
-
- if (!p) {
- ERR("BUG: trying to send offline winfo to empty presentity\n");
- return -1;
- }
-
- w = p->first_winfo_watcher;
- while (w) {
- if (w->status == WS_ACTIVE) {
- if (send_winfo_notify_offline(p, w, info, send_winfo_cb, info) == 0)
- return 0;
- }
- w = w->next;
- }
-
- return -1; /* impossible to send it */
- }
- int db_load_winfo(str *uid, str *events, str *domain, offline_winfo_t **infos)
- {
- int i, r = 0;
- db_res_t *res = NULL;
- db_key_t result_cols[] = {
- col_watcher, col_created_on, col_expires_on, col_dbid, col_status
- };
- db_key_t keys[] = { col_uid, col_events };
- db_op_t ops[] = { OP_EQ, OP_EQ };
- db_val_t k_vals[] = {
- { DB_STR, 0, { .str_val = *uid } }
- };
- offline_winfo_t *info = NULL;
- offline_winfo_t *last = NULL;
- *infos = NULL;
- if (pa_dbf.use_table(pa_db, offline_winfo_table) < 0) {
- ERR("Error in use_table\n");
- return -1;
- }
- if (pa_dbf.query (pa_db, keys, ops, k_vals,
- result_cols, 1, sizeof(result_cols) / sizeof(db_key_t),
- 0, &res) < 0) {
- ERR("Error while querying stored winfos\n");
- r = -1;
- res = NULL;
- }
- if (res) {
- for (i = 0; i < res->n; i++) {
- db_row_t *row = &res->rows[i];
- db_val_t *row_vals = ROW_VALUES(row);
- str watcher = STR_NULL;
- str status = STR_NULL;
- time_t created_on = 0;
- time_t expires_on = 0;
- int index = 0;
- get_str_val(row_vals[0], watcher);
- get_time_val(row_vals[1], created_on);
- get_time_val(row_vals[2], expires_on);
- get_int_val(row_vals[3], index);
- get_str_val(row_vals[4], status);
-
- info = create_winfo(uid, &watcher, events, domain, &status);
- if (!info) {
- r = -1;
- break;
- }
- info->created = created_on;
- info->expires = expires_on;
- info->index = index;
-
- if (last) last->next = info;
- else *infos = info;
- last = info;
- }
- pa_dbf.free_result(pa_db, res);
- }
- if ((*infos) && (r != 0)) {
- free_winfos(*infos);
- *infos = NULL;
- }
-
- return r;
- }
- /* ----- Handler functions ----- */
- #if 0
- /* not used due to problems with lost AVP after sending NOTIFY */
- static int get_status(str *dst)
- {
- avp_t *avp;
- int_str name, val;
- struct search_state s;
- str avp_subscription_status = STR_STATIC_INIT("subscription_status");
- /* if (!dst) return -1; */
-
- name.s = avp_subscription_status;
- avp = search_first_avp(AVP_CLASS_USER |
- AVP_TRACK_FROM | AVP_NAME_STR | AVP_VAL_STR, name, &val, 0);
- if (avp) {
- /* don't use default - use value from AVP */
- TRACE("subscription status = %.*s\n", FMT_STR(val.s));
- *dst = val.s;
- return 0;
- }
- else {
- /* leave default value!! */
- /* TRACE("left default subscription status\n"); */
- TRACE("subscription status AVP not found\n");
- }
-
- return 1;
- }
- #endif
- static void get_status_str(str *dst)
- {
- str s;
-
- switch(get_last_subscription_status()) {
- case WS_ACTIVE:
- s = watcher_status_names[WS_ACTIVE];
- break;
- case WS_REJECTED:
- case WS_PENDING_TERMINATED:
- case WS_TERMINATED:
- s = watcher_status_names[WS_TERMINATED];
- break;
- case WS_PENDING:
- s = watcher_status_names[WS_PENDING];
- break;
- default: str_clear(&s); /* throw out gcc complains */
- }
- if (dst) *dst = s;
- }
- int store_offline_winfo(struct sip_msg* _m, char* _domain, char* _table)
- {
- str uid = STR_NULL;
- str wuri = STR_NULL;
- str events = STR_NULL;
- str domain = STR_NULL;
- str status = STR_NULL;
- int res = -1;
- offline_winfo_t *info;
- if (get_presentity_uid(&uid, _m) < 0) {
- ERR("Error while extracting presentity UID\n");
- return 0; /* ??? impossible to return -1 or 1 */
- }
- get_watcher_uri(_m, &wuri);
- get_events(_m, &events);
- if (_domain) {
- domain.s = _domain;
- domain.len = strlen(_domain);
- }
- /* get stored subscription status value */
- get_status_str(&status);
- /* TRACE("subscription status is: %.*s\n", FMT_STR(status)); */
- info = create_winfo(&uid, &wuri, &events, &domain, &status);
- /* store it into database or use internal data structures too? */
- /* better to use only database because of lower memory usage - this
- * information could be stored for very long time ! */
-
- db_store_winfo(info);
-
- free_winfo(info); /* don't hold this information in memory ! */
- return res;
- }
- /* send offline winfo as regular watcher info NOTIFY if possible
- * (for presentity got from get_to) */
- int dump_offline_winfo(struct sip_msg* _m, char* _domain, char* _events)
- {
- struct pdomain* d;
- struct presentity *p;
- str uid = STR_NULL;
- int res = -1;
- str events;
- offline_winfo_t *info;
- d = (struct pdomain*)_domain;
- if (get_presentity_uid(&uid, _m) < 0) {
- ERR("Error while extracting presentity UID\n");
- return -1;
- }
-
- if (_events) {
- events.s = _events;
- events.len = strlen(_events);
- }
- if (db_load_winfo(&uid, &events, d->name, &info) != 0) {
- return -1;
- }
- if (!info) {
- return 1; /* nothing to do */
- }
- lock_pdomain(d);
- if (find_presentity_uid(d, &uid, &p) == 0) {
- /* presentity found */
- if (send_winfo(p, info) == 0) res = 1;
- else res = -1;
- }
- unlock_pdomain(d);
- return res;
- }
- void offline_winfo_timer(unsigned int ticks, void* param)
- {
- remove_expired_winfos();
- }
- int check_subscription_status(struct sip_msg* _m, char* _status, char* _x)
- {
- watcher_status_t status = (watcher_status_t)_status;
- if (status == get_last_subscription_status()) return 1;
- else return -1;
- }
- /* convert char* parameter to watcher_status_t */
- int check_subscription_status_fix(void **param, int param_no)
- {
- watcher_status_t status = WS_PENDING;
- char *s;
- str ss;
- if (param_no == 1) {
- s = (char*)*param;
- if (!s) {
- ERR("status not given!\n");
- return -1;
- }
-
- /* TRACE("status name is %s\n", (char*)*param); */
-
- ss.s = s;
- ss.len = strlen(s);
-
- status = watcher_status_from_string(&ss);
- *param = (void*)status;
- }
- return 0;
- }
|