publish.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. /*
  2. * Presence Agent, publish handling
  3. *
  4. * $Id$
  5. *
  6. * Copyright (C) 2001-2003 FhG Fokus
  7. * Copyright (C) 2003-2004 Hewlett-Packard Company
  8. *
  9. * This file is part of ser, a free SIP server.
  10. *
  11. * ser is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version
  15. *
  16. * For a license to use the ser software under conditions
  17. * other than those described here, or to purchase support for this
  18. * software, please contact iptel.org by e-mail at the following addresses:
  19. * [email protected]
  20. *
  21. * ser is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU General Public License
  27. * along with this program; if not, write to the Free Software
  28. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  29. *
  30. */
  31. #include <string.h>
  32. #include <stdlib.h>
  33. #include "../../str.h"
  34. #include "../../dprint.h"
  35. #include "../../mem/mem.h"
  36. #include "../../parser/parse_uri.h"
  37. #include "../../parser/parse_from.h"
  38. #include "../../parser/contact/parse_contact.h"
  39. #include "../../parser/parse_expires.h"
  40. #include "../../parser/parse_event.h"
  41. #include "dlist.h"
  42. #include "presentity.h"
  43. #include "watcher.h"
  44. #include "notify.h"
  45. #include "paerrno.h"
  46. #include "pdomain.h"
  47. #include "pa_mod.h"
  48. #include "ptime.h"
  49. #include "reply.h"
  50. #include "subscribe.h"
  51. #include "publish.h"
  52. #include "tuple.h"
  53. #include "pres_notes.h"
  54. #include "extension_elements.h"
  55. #include "../../data_lump_rpl.h"
  56. #include "../../parser/parse_sipifmatch.h"
  57. #include <libxml/parser.h>
  58. #include <libxml/xpath.h>
  59. #include <presence/pidf.h>
  60. #include <cds/logger.h>
  61. #include <cds/sstr.h>
  62. /* ------------ Helper functions ------------ */
  63. /*
  64. * Parse all header fields that will be needed
  65. * to handle a PUBLISH request
  66. */
  67. static int parse_publish_hfs(struct sip_msg* _m)
  68. {
  69. int rc = 0;
  70. if ((rc = parse_headers(_m, HDR_FROM_F | HDR_EVENT_F |
  71. HDR_EXPIRES_F | HDR_SIPIFMATCH_F |
  72. HDR_CONTENTTYPE_F | HDR_CONTENTLENGTH_F, 0))
  73. == -1) {
  74. paerrno = PA_PARSE_ERR;
  75. LOG(L_ERR, "parse_publish_hfs(): Error while parsing headers\n");
  76. return -1;
  77. }
  78. if (parse_from_header(_m) < 0) {
  79. paerrno = PA_FROM_ERR;
  80. LOG(L_ERR, "parse_publish_hfs(): From malformed or missing\n");
  81. return -6;
  82. }
  83. if (_m->event) {
  84. if (parse_event(_m->event) < 0) {
  85. paerrno = PA_EVENT_PARSE;
  86. LOG(L_ERR, "parse_publish_hfs(): Error while parsing Event header field\n");
  87. return -8;
  88. }
  89. } else {
  90. paerrno = PA_EVENT_PARSE;
  91. LOG(L_ERR, "parse_publish_hfs(): Missing Event header field\n");
  92. return -7;
  93. }
  94. if (_m->expires) {
  95. if (parse_expires(_m->expires) < 0) {
  96. paerrno = PA_EXPIRES_PARSE;
  97. LOG(L_ERR, "parse_publish_hfs(): Error while parsing Expires header field\n");
  98. return -9;
  99. }
  100. }
  101. /* patch from PIC-SER */
  102. if (_m->sipifmatch) {
  103. if (parse_sipifmatch(_m->sipifmatch) < 0) {
  104. paerrno = PA_PARSE_ERR;
  105. LOG(L_ERR, "parse_hfs(): Error while parsing SIP-If-Match header field\n");
  106. return -10;
  107. }
  108. }
  109. if (_m->content_type) {
  110. if (parse_content_type_hdr(_m) < 0) {
  111. LOG(L_ERR, "parse_hfs(): Can't parse Content-Type\n");
  112. return -12;
  113. }
  114. }
  115. return 0;
  116. }
  117. static inline void generate_etag(dbid_t dst, presentity_t *p)
  118. {
  119. generate_dbid_ptr(dst, p);
  120. }
  121. static void add_expires_to_rpl(struct sip_msg *_m, int expires)
  122. {
  123. char tmp[64];
  124. if (expires < 0) expires = 0;
  125. sprintf(tmp, "Expires: %d\r\n", expires);
  126. if (!add_lump_rpl(_m, tmp, strlen(tmp), LUMP_RPL_HDR)) {
  127. LOG(L_ERR, "Can't add expires header to the response\n");
  128. }
  129. }
  130. static void add_etag_to_rpl(struct sip_msg *_m, str *etag)
  131. {
  132. char *tmp;
  133. tmp = (char*)pkg_malloc(32 + etag->len);
  134. if (!tmp) {
  135. LOG(L_ERR, "Can't allocate package memory for SIP-ETag header to the response\n");
  136. return;
  137. }
  138. sprintf(tmp, "SIP-ETag: %.*s\r\n", etag->len, etag->s);
  139. if (!add_lump_rpl(_m, tmp, strlen(tmp), LUMP_RPL_HDR)) {
  140. LOG(L_ERR, "Can't add SIP-ETag header to the response\n");
  141. /* return -1; */
  142. }
  143. pkg_free(tmp);
  144. }
  145. /* ------------ publishing functions ------------ */
  146. static void add_presentity_notes(presentity_t *presentity, presentity_info_t *p, str *etag, time_t expires)
  147. {
  148. presence_note_t *n;
  149. pa_presence_note_t *pan;
  150. if (!p) return;
  151. n = p->first_note;
  152. while (n) {
  153. pan = presence_note2pa(n, etag, expires);
  154. if (pan) add_pres_note(presentity, pan);
  155. n = n->next;
  156. }
  157. }
  158. static void add_extension_elements(presentity_t *presentity, presentity_info_t *p, str *etag, time_t expires)
  159. {
  160. extension_element_t *n;
  161. pa_extension_element_t *pan;
  162. if (!p) return;
  163. n = p->first_unknown_element;
  164. while (n) {
  165. pan = extension_element2pa(n, etag, expires);
  166. if (pan) add_extension_element(presentity, pan);
  167. n = n->next;
  168. }
  169. }
  170. static void add_published_tuples(presentity_t *presentity, presentity_info_t *p, str *etag, time_t expires)
  171. {
  172. presence_tuple_info_t *i;
  173. presence_tuple_t *t;
  174. if (!p) return;
  175. i = p->first_tuple;
  176. while (i) {
  177. t = presence_tuple_info2pa(i, etag, expires);
  178. if (t) add_presence_tuple(presentity, t);
  179. i = i->next;
  180. }
  181. }
  182. static int update_published_tuples(presentity_t *presentity, presentity_info_t *p, str *etag, time_t expires)
  183. {
  184. presence_tuple_info_t *i;
  185. presence_tuple_t *t, *tt;
  186. int found = 0;
  187. double mark = -149.386;
  188. if (!p) return 0;
  189. /* mark tuples as unprocessed */
  190. t = get_first_tuple(presentity);
  191. while (t) {
  192. if (str_case_equals(&t->etag, etag) == 0) {
  193. t->data.priority = mark;
  194. found++;
  195. }
  196. t = get_next_tuple(t);
  197. }
  198. /* add previously not published tuples and update previously published */
  199. i = p->first_tuple;
  200. while (i) {
  201. t = find_published_tuple(presentity, etag, &i->id);
  202. if (t) {
  203. /* the tuple was published this way */
  204. found++;
  205. update_tuple(presentity, t, i, expires);
  206. }
  207. else {
  208. /* this tuple was not published => add it */
  209. t = presence_tuple_info2pa(i, etag, expires);
  210. if (t) add_presence_tuple(presentity, t);
  211. }
  212. i = i->next;
  213. }
  214. /* remove previously published tuples which were not processed (not present now) */
  215. t = get_first_tuple(presentity);
  216. while (t) {
  217. tt = get_next_tuple(t);
  218. if (t->data.priority == mark) {
  219. remove_presence_tuple(presentity, t);
  220. free_presence_tuple(t);
  221. }
  222. t = tt;
  223. }
  224. return found;
  225. }
  226. static int update_all_published_tuples(presentity_t *p, str *etag, time_t expires)
  227. {
  228. int found = 0;
  229. presence_tuple_t *tuple = get_first_tuple(p);
  230. while (tuple) {
  231. if (str_case_equals(&tuple->etag, etag) == 0) {
  232. tuple->expires = expires;
  233. found++;
  234. db_update_presence_tuple(p, tuple, 0);
  235. }
  236. tuple = get_next_tuple(tuple);
  237. }
  238. return found;
  239. }
  240. static int update_pres_notes(presentity_t *p, str *etag, time_t expires)
  241. {
  242. int found = 0;
  243. pa_presence_note_t *note = get_first_note(p);
  244. while (note) {
  245. if (str_case_equals(&note->etag, etag) == 0) {
  246. note->expires = expires;
  247. found++;
  248. db_update_pres_note(p, note);
  249. }
  250. note = get_next_note(note);
  251. }
  252. return found;
  253. }
  254. static int update_extension_elements(presentity_t *p, str *etag, time_t expires)
  255. {
  256. int found = 0;
  257. pa_extension_element_t *e = (pa_extension_element_t *)p->data.first_unknown_element;
  258. while (e) {
  259. if (str_case_equals(&e->etag, etag) == 0) {
  260. e->expires = expires;
  261. db_update_extension_element(p, e);
  262. found++;
  263. }
  264. e = (pa_extension_element_t *)e->data.next;
  265. }
  266. return found;
  267. }
  268. int process_published_presentity_info(presentity_t *presentity, presentity_info_t *p, str *etag,
  269. time_t expires, int has_etag)
  270. {
  271. if (!has_etag) {
  272. if (!p) return -1; /* must be published something */
  273. /* add all notes for presentity */
  274. add_presentity_notes(presentity, p, etag, expires);
  275. /* add all tuples */
  276. add_published_tuples(presentity, p, etag, expires);
  277. /* add all extension elements (RPID) */
  278. add_extension_elements(presentity, p, etag, expires);
  279. }
  280. else {
  281. if (p) {
  282. /* remove all notes for this etag */
  283. remove_pres_notes(presentity, etag);
  284. /* remove all extension elements (RPID) */
  285. remove_extension_elements(presentity, etag);
  286. /* add all notes for presentity */
  287. add_presentity_notes(presentity, p, etag, expires);
  288. update_published_tuples(presentity, p, etag, expires);
  289. add_extension_elements(presentity, p, etag, expires);
  290. }
  291. else {
  292. /* all expirations must be refreshed, nothing cleared */
  293. update_all_published_tuples(presentity, etag, expires);
  294. update_extension_elements(presentity, etag, expires);
  295. update_pres_notes(presentity, etag, expires);
  296. }
  297. }
  298. presentity->flags |= PFLAG_PRESENCE_CHANGED;
  299. return 0;
  300. }
  301. /* ------------ PUBLISH handling functions ------------ */
  302. static int publish_presence(struct sip_msg* _m, struct presentity* presentity)
  303. {
  304. char *body = get_body(_m);
  305. int body_len = 0;
  306. int msg_expires = default_expires;
  307. time_t expires = 0;
  308. str etag;
  309. dbid_t generated_etag;
  310. int has_etag;
  311. presentity_info_t *p = NULL;
  312. int content_type = -1;
  313. if (_m->content_type) content_type = get_content_type(_m);
  314. if (_m->content_length) body_len = get_content_length(_m);
  315. if (_m->expires) {
  316. if (_m->expires->parsed) {
  317. msg_expires = ((exp_body_t*)_m->expires->parsed)->val;
  318. }
  319. }
  320. if (msg_expires > max_publish_expiration)
  321. msg_expires = max_publish_expiration;
  322. if (msg_expires != 0) expires = msg_expires + act_time;
  323. if (_m->sipifmatch) {
  324. if (_m->sipifmatch->parsed)
  325. etag = *(str*)_m->sipifmatch->parsed;
  326. else str_clear(&etag);
  327. has_etag = 1;
  328. }
  329. else {
  330. /* ETag was not set, generate a new one */
  331. generate_dbid(generated_etag);
  332. etag.len = dbid_strlen(generated_etag);
  333. etag.s = dbid_strptr(generated_etag);
  334. has_etag = 0;
  335. }
  336. if (body_len > 0) {
  337. switch (content_type) {
  338. case MIMETYPE(APPLICATION,PIDFXML):
  339. if (parse_pidf_document(&p, body, body_len) != 0) {
  340. LOG(L_ERR, "can't parse PIDF document\n");
  341. paerrno = PA_UNSUPP_DOC; /* ? PA_PARSE_ERR */
  342. }
  343. break;
  344. case MIMETYPE(APPLICATION,CPIM_PIDFXML):
  345. if (parse_cpim_pidf_document(&p, body, body_len) != 0) {
  346. LOG(L_ERR, "can't parse CPIM-PIDF document\n");
  347. paerrno = PA_UNSUPP_DOC;
  348. }
  349. break;
  350. default:
  351. LOG(L_ERR, "unsupported Content-Type 0x%x for PUBLISH handling\n",
  352. content_type);
  353. paerrno = PA_UNSUPP_DOC;
  354. }
  355. if (paerrno != PA_OK) return -1;
  356. }
  357. if (process_published_presentity_info(presentity, p, &etag,
  358. expires, has_etag) == 0) {
  359. /* add header fields into response */
  360. add_expires_to_rpl(_m, msg_expires);
  361. add_etag_to_rpl(_m, &etag);
  362. }
  363. if (p) free_presentity_info(p);
  364. return 0;
  365. }
  366. static int publish_presentity(struct sip_msg* _m, struct pdomain* _d, struct presentity* presentity)
  367. {
  368. event_t *parsed_event = NULL;
  369. int event_package = EVENT_OTHER;
  370. str callid = STR_STATIC_INIT("???");
  371. int res;
  372. if (_m->event)
  373. parsed_event = (event_t *)_m->event->parsed;
  374. if (parsed_event)
  375. event_package = parsed_event->parsed;
  376. LOG(L_DBG, "publish_presentity: event_package=%d -1-\n", event_package);
  377. switch (event_package) {
  378. case EVENT_PRESENCE:
  379. res = publish_presence(_m, presentity);
  380. break;
  381. default:
  382. if (_m->callid) callid = _m->callid->body;
  383. LOG(L_WARN, "publish_presentity: no handler for event_package=%d"
  384. " callid=%.*s\n", event_package, callid.len, ZSW(callid.s));
  385. paerrno = PA_EVENT_UNSUPP;
  386. res = -1;
  387. }
  388. return res;
  389. }
  390. /*
  391. * Handle a publish Request
  392. */
  393. int handle_publish(struct sip_msg* _m, char* _domain, char* _s2)
  394. {
  395. struct pdomain* d;
  396. struct presentity *p;
  397. str p_uri = STR_NULL;
  398. str uid = STR_NULL;
  399. xcap_query_params_t xcap_params;
  400. get_act_time();
  401. paerrno = PA_OK;
  402. if (parse_publish_hfs(_m) < 0) {
  403. LOG(L_ERR, "handle_publish(): Error while parsing message header\n");
  404. goto error;
  405. }
  406. d = (struct pdomain*)_domain;
  407. if (get_pres_uri(_m, &p_uri) < 0 || p_uri.s == NULL || p_uri.len == 0) {
  408. LOG(L_ERR, "handle_publish(): Error while extracting presentity URI\n");
  409. goto error;
  410. }
  411. if (get_presentity_uid(&uid, _m) < 0) {
  412. ERR("Error while extracting presentity UID\n");
  413. goto error;
  414. }
  415. lock_pdomain(d);
  416. if (find_presentity_uid(d, &uid, &p) > 0) {
  417. memset(&xcap_params, 0, sizeof(xcap_params));
  418. if (fill_xcap_params) fill_xcap_params(_m, &xcap_params);
  419. if (new_presentity(d, &p_uri, &uid, &xcap_params, &p) < 0) {
  420. LOG(L_ERR, "handle_publish can't create presentity\n");
  421. goto error2;
  422. }
  423. }
  424. /* update presentity event state */
  425. if (p) publish_presentity(_m, d, p);
  426. unlock_pdomain(d);
  427. if (send_reply(_m) < 0) return -1;
  428. return 1;
  429. error2:
  430. unlock_pdomain(d);
  431. error:
  432. send_reply(_m);
  433. return 0;
  434. }