#include "presentity.h" #include #include "paerrno.h" #include "pa_mod.h" #include "tuple.h" #include "tuple_notes.h" #include "tuple_extensions.h" void add_presence_tuple_no_wb(presentity_t *_p, presence_tuple_t *_t); /* * Create a new presence_tuple */ int new_presence_tuple(str* _contact, time_t expires, presence_tuple_t ** _t, int is_published, str *id, str *published_id, str *etag) { presence_tuple_t* tuple; int size = 0; int len; dbid_t tmp; if (!_t) { paerrno = PA_INTERNAL_ERROR; ERR("Invalid parameter value\n"); return -1; } if (!id) { /* always needed (for PIDF documents, ...) */ generate_dbid(tmp); len = dbid_strlen(tmp); } else len = id->len; size = sizeof(presence_tuple_t); if (etag) size += etag->len; if (published_id) size += published_id->len; if (!is_published) { if (_contact) size += _contact->len; /* Non-published tuples have contact allocated * together with other data! */ } size += len; tuple = (presence_tuple_t*)mem_alloc(size); if (!tuple) { paerrno = PA_NO_MEMORY; ERR("No memory left: size=%d\n", size); return -1; } memset(tuple, 0, sizeof(presence_tuple_t)); tuple->data.status.basic = presence_tuple_undefined_status; tuple->data.id.s = ((char*)tuple) + sizeof(presence_tuple_t); if (id) str_cpy(&tuple->data.id, id); else dbid_strcpy(&tuple->data.id, tmp, len); tuple->etag.s = after_str_ptr(&tuple->data.id); if (etag) str_cpy(&tuple->etag, etag); else tuple->etag.len = 0; tuple->published_id.s = after_str_ptr(&tuple->etag); if (published_id) str_cpy(&tuple->published_id, published_id); else tuple->published_id.len = 0; if (is_published) { str_dup(&tuple->data.contact, _contact); /* published contacts can change */ } else { /* non-published contacts can NOT change !!! */ tuple->data.contact.s = after_str_ptr(&tuple->published_id); if (_contact) str_cpy(&tuple->data.contact, _contact); else tuple->data.contact.len = 0; } tuple->expires = expires; tuple->data.priority = default_priority; tuple->is_published = is_published; *_t = tuple; return 0; } int db_read_tuples(presentity_t *_p, db_con_t* db) { db_key_t keys[] = { col_pres_id }; db_op_t ops[] = { OP_EQ }; db_val_t k_vals[] = { { DB_STR, 0, { .str_val = _p->pres_id } } }; int i; int r = 0; db_res_t *res = NULL; db_key_t result_cols[] = { col_basic, col_expires, col_priority, col_contact, col_tupleid, col_etag, col_published_id } ; if (!use_db) return 0; if (pa_dbf.use_table(db, presentity_contact_table) < 0) { ERR("Error in use_table\n"); return -1; } if (pa_dbf.query (db, keys, ops, k_vals, result_cols, 1, sizeof(result_cols) / sizeof(db_key_t), 0, &res) < 0) { ERR("Error while querying DB\n"); return -1; } if (!res) return 0; /* ? */ for (i = 0; i < res->n; i++) { presence_tuple_t *tuple = NULL; db_row_t *row = &res->rows[i]; db_val_t *row_vals = ROW_VALUES(row); str contact = STR_NULL; basic_tuple_status_t basic = presence_tuple_undefined_status; str id = STR_NULL; str etag = STR_NULL; str published_id = STR_NULL; time_t expires = 0; double priority = row_vals[2].val.double_val; #define get_str_val(i,dst) do{if(!row_vals[i].nul){dst.s=(char*)row_vals[i].val.string_val;dst.len=strlen(dst.s);}}while(0) #define get_int_val(i,dst) do{if(!row_vals[i].nul){dst=row_vals[i].val.int_val;}}while(0) #define get_time_val(i,dst) do{if(!row_vals[i].nul){dst=row_vals[i].val.time_val;}}while(0) get_int_val(0, basic); get_time_val(1, expires); get_str_val(3, contact); get_str_val(4, id); get_str_val(5, etag); get_str_val(6, published_id); #undef get_str_val #undef get_time_val r = new_presence_tuple(&contact, expires, &tuple, 1, &id, &published_id, &etag) | r; if (tuple) { tuple->data.status.basic = basic; LOG(L_DBG, "read tuple %.*s\n", id.len, id.s); tuple->data.priority = priority; db_read_tuple_notes(_p, tuple, db); db_read_tuple_extensions(_p, tuple, db); add_presence_tuple_no_wb(_p, tuple); } } pa_dbf.free_result(db, res); return r; } static int set_tuple_db_data(presentity_t *_p, presence_tuple_t *tuple, db_key_t *cols, db_val_t *vals, int *col_cnt) { int n_updates = 0; cols[n_updates] = col_tupleid; vals[n_updates].type = DB_STR; vals[n_updates].nul = 0; vals[n_updates].val.str_val = tuple->data.id; n_updates++; cols[n_updates] = col_pres_id; vals[n_updates].type = DB_STR; vals[n_updates].nul = 0; vals[n_updates].val.str_val = _p->pres_id; n_updates++; cols[n_updates] = col_basic; vals[n_updates].type = DB_INT; vals[n_updates].nul = 0; vals[n_updates].val.int_val = tuple->data.status.basic; n_updates++; cols[n_updates] = col_contact; vals[n_updates].type = DB_STR; vals[n_updates].nul = 0; vals[n_updates].val.str_val = tuple->data.contact; n_updates++; cols[n_updates] = col_etag; vals[n_updates].type = DB_STR; vals[n_updates].nul = 0; vals[n_updates].val.str_val = tuple->etag; n_updates++; cols[n_updates] = col_published_id; vals[n_updates].type = DB_STR; vals[n_updates].nul = 0; vals[n_updates].val.str_val = tuple->published_id; n_updates++; if (tuple->data.priority != 0.0) { cols[n_updates] = col_priority; vals[n_updates].type = DB_DOUBLE; vals[n_updates].nul = 0; vals[n_updates].val.double_val = tuple->data.priority; n_updates++; } if (tuple->expires != 0) { cols[n_updates] = col_expires; vals[n_updates].type = DB_DATETIME; vals[n_updates].nul = 0; vals[n_updates].val.time_val = tuple->expires; n_updates++; } *col_cnt = n_updates; return 0; } static int db_add_presence_tuple(presentity_t *_p, presence_tuple_t *t) { db_key_t query_cols[20]; db_val_t query_vals[20]; int n_query_cols = 0; int res; if (!use_db) return 0; if (!t->is_published) return 0; /* store only published tuples */ if (set_tuple_db_data(_p, t, query_cols, query_vals, &n_query_cols) != 0) { return -1; } if (pa_dbf.use_table(pa_db, presentity_contact_table) < 0) { LOG(L_ERR, "db_add_presence_tuple: Error in use_table\n"); return -1; } if (pa_dbf.insert(pa_db, query_cols, query_vals, n_query_cols) < 0) { LOG(L_ERR, "db_add_presence_tuple: Can't insert record\n"); return -1; } res = 0; if (db_add_tuple_notes(_p, t) < 0) { res = -2; ERR("can't add tuple notes into DB\n"); } if (db_add_tuple_extensions(_p, t) < 0) { res = -3; ERR("can't add tuple extensions into DB\n"); } return res; } static int db_remove_presence_tuple(presentity_t *_p, presence_tuple_t *t) { db_key_t keys[] = { col_pres_id, col_tupleid }; db_op_t ops[] = { OP_EQ, OP_EQ }; db_val_t k_vals[] = { { DB_STR, 0, { .str_val = _p->pres_id } }, { DB_STR, 0, { .str_val = t->data.id } } }; if (!use_db) return 0; if (!t->is_published) return 0; /* store only published tuples */ db_remove_tuple_notes(_p, t); db_remove_tuple_extensions(_p, t); if (pa_dbf.use_table(pa_db, presentity_contact_table) < 0) { LOG(L_ERR, "db_remove_presence_tuple: Error in use_table\n"); return -1; } if (pa_dbf.delete(pa_db, keys, ops, k_vals, 2) < 0) { LOG(L_ERR, "db_remove_presence_tuple: Can't delete record\n"); return -1; } return 0; } int db_update_presence_tuple(presentity_t *_p, presence_tuple_t *t, int update_notes_and_ext) { db_key_t keys[] = { col_pres_id, col_tupleid }; db_op_t ops[] = { OP_EQ, OP_EQ }; db_val_t k_vals[] = { { DB_STR, 0, { .str_val = _p->pres_id } }, { DB_STR, 0, { .str_val = t->data.id } } }; db_key_t query_cols[20]; db_val_t query_vals[20]; int n_query_cols = 0; if (!use_db) return 0; if (!t->is_published) return 0; /* store only published tuples */ if (set_tuple_db_data(_p, t, query_cols, query_vals, &n_query_cols) != 0) { return -1; } if (pa_dbf.use_table(pa_db, presentity_contact_table) < 0) { ERR("Error in use_table\n"); return -1; } if (pa_dbf.update(pa_db, keys, ops, k_vals, query_cols, query_vals, 2, n_query_cols) < 0) { ERR("Can't update record\n"); return -1; } if (update_notes_and_ext) { db_update_tuple_notes(_p, t); db_update_tuple_extensions(_p, t); } return 0; } void add_presence_tuple_no_wb(presentity_t *_p, presence_tuple_t *_t) { DOUBLE_LINKED_LIST_ADD(_p->data.first_tuple, _p->data.last_tuple, (presence_tuple_info_t*)_t); } void add_presence_tuple(presentity_t *_p, presence_tuple_t *_t) { add_presence_tuple_no_wb(_p, _t); if (use_db) db_add_presence_tuple(_p, _t); } void remove_presence_tuple(presentity_t *_p, presence_tuple_t *_t) { DOUBLE_LINKED_LIST_REMOVE(_p->data.first_tuple, _p->data.last_tuple, (presence_tuple_info_t*)_t); if (use_db) db_remove_presence_tuple(_p, _t); } /* * Free all memory associated with a presence_tuple */ void free_presence_tuple(presence_tuple_t * _t) { if (_t) { free_tuple_notes(_t); free_tuple_extensions(_t); if (_t->is_published) { /* Warning: not-published tuples have contact allocated * together with other data => contact can't change! */ str_free_content(&_t->data.contact); } mem_free(_t); } } /* * Find a presence_tuple for contact _contact on presentity _p */ int find_registered_presence_tuple(str* _contact, presentity_t *_p, presence_tuple_t ** _t) { presence_tuple_t *tuple; if (!_contact || !_contact->len || !_p || !_t) { paerrno = PA_INTERNAL_ERROR; LOG(L_ERR, "find_presence_tuple(): Invalid parameter value\n"); return -1; } tuple = get_first_tuple(_p); while (tuple) { /* only contacts from usrloc should have unique contact - published * may be more times !!! */ if (!tuple->is_published) { if (str_nocase_equals(&tuple->data.contact, _contact) == 0) { *_t = tuple; return 0; } } tuple = (presence_tuple_t*)tuple->data.next; } return 1; } /* * Find a presence_tuple on presentity _p */ int find_presence_tuple_id(str* id, presentity_t *_p, presence_tuple_t ** _t) { presence_tuple_t *tuple; if (!id || !id->len || !_p || !_t) { paerrno = PA_INTERNAL_ERROR; LOG(L_ERR, "find_presence_tuple_id(): Invalid parameter value\n"); return -1; } tuple = get_first_tuple(_p); while (tuple) { if (str_case_equals(&tuple->data.id, id) == 0) { *_t = tuple; return 0; } tuple = (presence_tuple_t*)tuple->data.next; } return 1; } presence_tuple_t *find_published_tuple(presentity_t *presentity, str *etag, str *id) { presence_tuple_t *tuple = get_first_tuple(presentity); while (tuple) { if (str_case_equals(&tuple->etag, etag) == 0) { if (str_case_equals(&tuple->published_id, id) == 0) return tuple; } tuple = get_next_tuple(tuple); } return NULL; } static inline void dup_tuple_notes(presence_tuple_t *dst, presence_tuple_info_t *src) { presence_note_t *n, *nn; n = src->first_note; while (n) { nn = create_presence_note(&n->value, &n->lang); if (nn) add_tuple_note_no_wb(dst, nn); n = n->next; } } static inline void dup_tuple_extensions(presence_tuple_t *dst, presence_tuple_info_t *src) { extension_element_t *e, *ne; e = src->first_unknown_element; while (e) { ne = create_extension_element(&e->element); if (ne) add_tuple_extension_no_wb(dst, ne, 0); e = e->next; } /* add new extensions for tuple status */ e = src->status.first_unknown_element; while (e) { ne = create_extension_element(&e->element); if (ne) add_tuple_extension_no_wb(dst, ne, 1); e = e->next; } } presence_tuple_t *presence_tuple_info2pa(presence_tuple_info_t *i, str *etag, time_t expires) { presence_tuple_t *t = NULL; int res; /* ID for the tuple is newly generated ! */ res = new_presence_tuple(&i->contact, expires, &t, 1, NULL, &i->id, etag); if (res != 0) return NULL; t->data.priority = i->priority; t->data.status.basic = i->status.basic; /* add notes for tuple */ dup_tuple_notes(t, i); /* add all extension elements */ dup_tuple_extensions(t, i); return t; } void update_tuple(presentity_t *p, presence_tuple_t *t, presence_tuple_info_t *i, time_t expires) { t->expires = expires; t->data.priority = i->priority; t->data.status.basic = i->status.basic; str_free_content(&t->data.contact); str_dup(&t->data.contact, &i->contact); /* remove all old notes and extension elements for this tuple */ free_tuple_notes(t); free_tuple_extensions(t); /* add new notes and new extension elemens for tuple */ dup_tuple_notes(t, i); dup_tuple_extensions(t, i); if (use_db) db_update_presence_tuple(p, t, 1); }