Browse code

presence: handle publish with full records stored in cache

Daniel-Constantin Mierla authored on 20/04/2020 13:26:39
Showing 6 changed files
... ...
@@ -28,6 +28,7 @@
28 28
 
29 29
 #include <stdio.h>
30 30
 #include <stdlib.h>
31
+#include <time.h>
31 32
 #include "../../core/mem/shm_mem.h"
32 33
 #include "../../core/hashes.h"
33 34
 #include "../../core/dprint.h"
... ...
@@ -999,7 +1000,7 @@ int ps_ptable_insert(ps_presentity_t *pt)
999 1000
 /**
1000 1001
  *
1001 1002
  */
1002
-int ps_ptable_update(ps_presentity_t *pt)
1003
+int ps_ptable_replace(ps_presentity_t *pt)
1003 1004
 {
1004 1005
 	ps_presentity_t ptc;
1005 1006
 	ps_presentity_t *ptn = NULL;
... ...
@@ -1054,6 +1055,70 @@ int ps_ptable_update(ps_presentity_t *pt)
1054 1055
 	return 0;
1055 1056
 }
1056 1057
 
1058
+/**
1059
+ *
1060
+ */
1061
+int ps_ptable_update(ps_presentity_t *pt)
1062
+{
1063
+	ps_presentity_t ptc;
1064
+	ps_presentity_t *ptn = NULL;
1065
+	int idx = 0;
1066
+
1067
+	/* copy struct to fill in missing fields */
1068
+	memcpy(&ptc, pt, sizeof(ps_presentity_t));
1069
+
1070
+	ptc.hashid = core_case_hash(&pt->user, &pt->domain, 0);
1071
+
1072
+	if(ptc.ruid.s == NULL) {
1073
+		if(sruid_next(&pres_sruid) < 0) {
1074
+			return -1;
1075
+		}
1076
+		ptc.ruid = pres_sruid.uid;
1077
+	}
1078
+
1079
+	idx = ptn->hashid % _ps_ptable->ssize;
1080
+
1081
+	lock_get(&_ps_ptable->slots[idx].lock);
1082
+	ptn = _ps_ptable->slots[idx].plist;
1083
+	while(ptn!=NULL) {
1084
+		if(ps_presentity_match(ptn, &ptc, 0)==1) {
1085
+			if(ptn->next) {
1086
+				ptn->next->prev = ptn->prev;
1087
+			}
1088
+			if(ptn->prev) {
1089
+				ptn->prev->next = ptn->next;
1090
+			} else {
1091
+				_ps_ptable->slots[idx].plist = ptn->next;
1092
+			}
1093
+			break;
1094
+		}
1095
+		ptn = ptn->next;
1096
+	}
1097
+
1098
+	if(ptn == NULL) {
1099
+		lock_release(&_ps_ptable->slots[idx].lock);
1100
+		return 0; /* affected items */
1101
+	}
1102
+	ps_presentity_free(ptn, 0);
1103
+
1104
+	ptn = ps_presentity_new(&ptc, 0);
1105
+	if(ptn==NULL) {
1106
+		lock_release(&_ps_ptable->slots[idx].lock);
1107
+		return -1;
1108
+	}
1109
+
1110
+	if(_ps_ptable->slots[idx].plist == NULL) {
1111
+		_ps_ptable->slots[idx].plist = ptn;
1112
+	} else {
1113
+		_ps_ptable->slots[idx].plist->prev = ptn;
1114
+		ptn->next = _ps_ptable->slots[idx].plist;
1115
+		_ps_ptable->slots[idx].plist = ptn;
1116
+	}
1117
+	lock_release(&_ps_ptable->slots[idx].lock);
1118
+
1119
+	return 1; /* affected items */
1120
+}
1121
+
1057 1122
 /**
1058 1123
  *
1059 1124
  */
... ...
@@ -1171,4 +1236,45 @@ ps_presentity_t *ps_ptable_get_item(str *user, str *domain, str *event, str *eta
1171 1236
 	lock_release(&_ps_ptable->slots[idx].lock);
1172 1237
 
1173 1238
 	return ptd;
1239
+}
1240
+
1241
+/**
1242
+ *
1243
+ */
1244
+ps_presentity_t *ps_ptable_get_expired(int eval)
1245
+{
1246
+	ps_presentity_t *ptn = NULL;
1247
+	ps_presentity_t *ptl = NULL;
1248
+	ps_presentity_t *ptd = NULL;
1249
+	ps_presentity_t *pte = NULL;
1250
+	int i = 0;
1251
+
1252
+	for(i=0; i<_ps_ptable->ssize; i++) {
1253
+		lock_get(&_ps_ptable->slots[i].lock);
1254
+		ptn = _ps_ptable->slots[i].plist;
1255
+		while(ptn!=NULL) {
1256
+			if(ptn->expires > 0 && ptn->expires <= eval) {
1257
+				ptd = ps_presentity_dup(ptn, 1);
1258
+				if(ptd == NULL) {
1259
+					break;
1260
+				}
1261
+				if(pte==NULL) {
1262
+					ptl = ptd;
1263
+				} else {
1264
+					pte->next = ptd;
1265
+					ptd->prev = pte;
1266
+				}
1267
+				pte = ptd;
1268
+			}
1269
+			ptn = ptn->next;
1270
+		}
1271
+		lock_release(&_ps_ptable->slots[i].lock);
1272
+	}
1273
+
1274
+	if(ptd==NULL && ptl != NULL) {
1275
+		ps_presentity_list_free(ptl, 1);
1276
+		return NULL;
1277
+	}
1278
+
1279
+	return ptl;
1174 1280
 }
1175 1281
\ No newline at end of file
... ...
@@ -174,8 +174,11 @@ int ps_presentity_match(ps_presentity_t *pta, ps_presentity_t *ptb, int mmode);
174 174
 int ps_ptable_init(int ssize);
175 175
 void ps_ptable_destroy(void);
176 176
 int ps_ptable_insert(ps_presentity_t *pt);
177
+int ps_ptable_replace(ps_presentity_t *pt);
177 178
 int ps_ptable_update(ps_presentity_t *pt);
179
+int ps_ptable_remove(ps_presentity_t *pt);
178 180
 ps_presentity_t *ps_ptable_get_list(str *user, str *domain);
179 181
 ps_presentity_t *ps_ptable_get_item(str *user, str *domain, str *event, str *etag);
182
+ps_presentity_t *ps_ptable_get_expired(int eval);
180 183
 
181 184
 #endif
... ...
@@ -435,9 +435,15 @@ static int mod_init(void)
435 435
 		if(pres_timer_mode==0) {
436 436
 			register_timer(msg_presentity_clean, 0, pres_clean_period);
437 437
 			register_timer(msg_watchers_clean, 0, pres_clean_period);
438
+			if(publ_cache_mode==PS_PCACHE_RECORD) {
439
+				register_timer(ps_ptable_timer_clean, 0, pres_clean_period);
440
+			}
438 441
 		} else {
439 442
 			sr_wtimer_add(msg_presentity_clean, 0, pres_clean_period);
440 443
 			sr_wtimer_add(msg_watchers_clean, 0, pres_clean_period);
444
+			if(publ_cache_mode==PS_PCACHE_RECORD) {
445
+				sr_wtimer_add(ps_ptable_timer_clean, 0, pres_clean_period);
446
+			}
441 447
 		}
442 448
 	}
443 449
 
... ...
@@ -543,9 +543,9 @@ int ps_match_dialog_state(presentity_t *presentity, char *vstate)
543 543
 	return rmatch;
544 544
 }
545 545
 
546
-int update_presentity(struct sip_msg *msg, presentity_t *presentity, str *body,
547
-		int new_t, int *sent_reply, char *sphere, str *etag_override, str *ruid,
548
-		int replace)
546
+static int ps_db_update_presentity(sip_msg_t *msg, presentity_t *presentity,
547
+		str *body, int new_t, int *sent_reply, char *sphere, str *etag_override,
548
+		str *ruid, int replace)
549 549
 {
550 550
 	db_key_t query_cols[14], rquery_cols[2], update_keys[9], result_cols[7];
551 551
 	db_op_t query_ops[14], rquery_ops[2];
... ...
@@ -1294,6 +1294,492 @@ error:
1294 1294
 	return ret;
1295 1295
 }
1296 1296
 
1297
+static int ps_cache_update_presentity(sip_msg_t *msg, presentity_t *presentity,
1298
+		str *body, int new_t, int *sent_reply, char *sphere, str *etag_override,
1299
+		str *ruid, int replace)
1300
+{
1301
+	char *dot = NULL;
1302
+	str etag = STR_NULL;
1303
+	str crt_etag = STR_NULL;
1304
+	str *rules_doc = NULL;
1305
+	str pres_uri = STR_NULL;
1306
+	str old_body = STR_NULL;
1307
+	str sender = STR_NULL;
1308
+	int is_dialog = 0;
1309
+	int bla_update_publish = 1;
1310
+	int affected_rows = 0;
1311
+	int ret = -1;
1312
+	int cache_record_exists = 0;
1313
+	int num_watchers = 0;
1314
+	char *old_dialog_id = NULL;
1315
+	char *dialog_id = NULL;
1316
+	str crt_ruid = STR_NULL;
1317
+	str p_ruid = STR_NULL;
1318
+	ps_presentity_t ptc;
1319
+	ps_presentity_t *ptx = NULL;
1320
+
1321
+	if(sent_reply) {
1322
+		*sent_reply = 0;
1323
+	}
1324
+	memset(&ptc, 0, sizeof(ps_presentity_t));
1325
+
1326
+	/* here pres_notifier_processes == 0 -- used for db-only */
1327
+	if(presentity->event->req_auth) {
1328
+		/* get rules_document */
1329
+		if(presentity->event->get_rules_doc(
1330
+				   &presentity->user, &presentity->domain, &rules_doc)
1331
+				< 0) {
1332
+			LM_ERR("getting rules doc\n");
1333
+			goto error;
1334
+		}
1335
+	}
1336
+
1337
+	if(uandd_to_uri(presentity->user, presentity->domain, &pres_uri) < 0) {
1338
+		LM_ERR("constructing uri from user and domain\n");
1339
+		goto error;
1340
+	}
1341
+
1342
+	ptc.user = presentity->user;
1343
+	ptc.domain = presentity->domain;
1344
+	ptc.event = presentity->event->name;
1345
+	ptc.etag = presentity->etag;
1346
+
1347
+	if(new_t) {
1348
+		LM_DBG("new presentity with etag %.*s\n", presentity->etag.len,
1349
+				presentity->etag.s);
1350
+
1351
+		if(ruid) {
1352
+			/* use the provided ruid */
1353
+			p_ruid = *ruid;
1354
+		} else {
1355
+			/* generate a new ruid */
1356
+			if(sruid_next(&pres_sruid) < 0)
1357
+				goto error;
1358
+			p_ruid = pres_sruid.uid;
1359
+		}
1360
+		if(presentity->sender) {
1361
+			ptc.sender = *presentity->sender;
1362
+		} else {
1363
+			ptc.sender.s = "";
1364
+			ptc.sender.len = 0;
1365
+		}
1366
+		ptc.body = *body;
1367
+		ptc.received_time = presentity->received_time;
1368
+		ptc.priority = presentity->priority;
1369
+		ptc.ruid = p_ruid;
1370
+
1371
+		LM_DBG("adding new htable record\n");
1372
+		if(presentity->expires == -1) {
1373
+			replace = 1;
1374
+		}
1375
+		if(!replace) {
1376
+			/* A real PUBLISH */
1377
+			ptc.expires = presentity->expires + (int)time(NULL);
1378
+			if(presentity->event->evp->type == EVENT_DIALOG) {
1379
+				check_if_dialog(*body, &is_dialog, &dialog_id);
1380
+				if(dialog_id) {
1381
+					if(delete_presentity_if_dialog_id_exists(
1382
+							   presentity, dialog_id)
1383
+							< 0) {
1384
+						free(dialog_id);
1385
+						dialog_id = NULL;
1386
+						goto error;
1387
+					}
1388
+
1389
+					free(dialog_id);
1390
+					dialog_id = NULL;
1391
+				}
1392
+			}
1393
+			LM_DBG("inserting presentity into hash table\n");
1394
+			if(ps_ptable_insert(&ptc) < 0) {
1395
+				LM_ERR("inserting new record in database\n");
1396
+				goto error;
1397
+			}
1398
+		} else {
1399
+			/* A hard-state PUBLISH */
1400
+			ptc.expires = -1;
1401
+			if(presentity->expires != -1) {
1402
+				ptc.expires = presentity->expires + (int)time(NULL);
1403
+			}
1404
+			/* update/replace in memory */
1405
+			if(ps_ptable_replace(&ptc) <0) {
1406
+				LM_ERR("replacing record in database\n");
1407
+				goto error;
1408
+			}
1409
+		}
1410
+		if(publ_send200ok(msg, presentity->expires, presentity->etag) < 0) {
1411
+			LM_ERR("sending 200OK\n");
1412
+			goto error;
1413
+		}
1414
+		if(sent_reply) {
1415
+			*sent_reply = 1;
1416
+		}
1417
+		goto send_notify;
1418
+	} else {
1419
+		LM_DBG("updating existing presentity with etag %.*s\n",
1420
+				presentity->etag.len, presentity->etag.s);
1421
+
1422
+		if(ruid) {
1423
+			p_ruid = *ruid;
1424
+		}
1425
+		if(EVENT_DIALOG_SLA(presentity->event->evp)) {
1426
+			ptx = ps_ptable_get_item(&ptc.user, &ptc.domain, &ptc.event,
1427
+					&ptc.etag);
1428
+			if(ptx == NULL) {
1429
+				goto send_412;
1430
+			}
1431
+			cache_record_exists = 1;
1432
+			if(!p_ruid.s && ptx->ruid.s) {
1433
+				crt_ruid.len = ptx->ruid.len;
1434
+				crt_ruid.s = (char *)pkg_malloc(sizeof(char) * crt_ruid.len);
1435
+				if(!crt_ruid.s) {
1436
+					LM_ERR("no private memory\n");
1437
+					goto error;
1438
+				}
1439
+				memcpy(crt_ruid.s, ptx->ruid.s, crt_ruid.len);
1440
+				p_ruid = crt_ruid;
1441
+			}
1442
+
1443
+			old_body = ptx->body;
1444
+			if(check_if_dialog(*body, &is_dialog, &dialog_id) < 0) {
1445
+				LM_ERR("failed to check if dialog stored\n");
1446
+				if(dialog_id) {
1447
+					free(dialog_id);
1448
+					dialog_id = NULL;
1449
+				}
1450
+				goto error;
1451
+			}
1452
+
1453
+			free(dialog_id);
1454
+
1455
+			if(is_dialog == 1) {
1456
+				/* if the new body has a dialog - overwrite */
1457
+				goto after_dialog_check;
1458
+			}
1459
+			if(check_if_dialog(old_body, &is_dialog, &old_dialog_id) < 0) {
1460
+				LM_ERR("failed to check if dialog stored\n");
1461
+				if(old_dialog_id) {
1462
+					free(old_dialog_id);
1463
+					old_dialog_id = NULL;
1464
+				}
1465
+				goto error;
1466
+			}
1467
+
1468
+			/* if the old body has no dialog - overwrite */
1469
+			if(is_dialog == 0) {
1470
+				if(old_dialog_id) {
1471
+					free(old_dialog_id);
1472
+					old_dialog_id = NULL;
1473
+				}
1474
+				goto after_dialog_check;
1475
+			}
1476
+
1477
+			if(old_dialog_id) {
1478
+				free(old_dialog_id);
1479
+				old_dialog_id = NULL;
1480
+			}
1481
+
1482
+			sender = ptx->sender;
1483
+
1484
+			LM_DBG("old_sender = %.*s\n", sender.len, sender.s);
1485
+			if(presentity->sender) {
1486
+				if(!(presentity->sender->len == sender.len
1487
+						   && presence_sip_uri_match(
1488
+									  presentity->sender, &sender)
1489
+									  == 0))
1490
+					bla_update_publish = 0;
1491
+			}
1492
+after_dialog_check:
1493
+			ps_presentity_free(ptx, 1);
1494
+			ptx = NULL;
1495
+		}
1496
+
1497
+		if(presentity->expires <= 0) {
1498
+
1499
+			if(!cache_record_exists) {
1500
+				ptx = ps_ptable_get_item(&ptc.user, &ptc.domain, &ptc.event,
1501
+						&ptc.etag);
1502
+				if(ptx == NULL) {
1503
+					goto send_412;
1504
+				}
1505
+				cache_record_exists = 1;
1506
+				if(!p_ruid.s && ptx->ruid.s) {
1507
+					crt_ruid.len = ptx->ruid.len;
1508
+					crt_ruid.s = (char *)pkg_malloc(sizeof(char) * crt_ruid.len);
1509
+					if(!crt_ruid.s) {
1510
+						LM_ERR("no private memory\n");
1511
+						goto error;
1512
+					}
1513
+					memcpy(crt_ruid.s, ptx->ruid.s, crt_ruid.len);
1514
+					p_ruid = crt_ruid;
1515
+				}
1516
+				ps_presentity_free(ptx, 1);
1517
+				ptx = NULL;
1518
+			}
1519
+			if(publ_send200ok(msg, presentity->expires, presentity->etag) < 0) {
1520
+				LM_ERR("sending 200OK reply\n");
1521
+				goto error;
1522
+			}
1523
+			if(sent_reply) {
1524
+				*sent_reply = 1;
1525
+			}
1526
+
1527
+			if(publ_notify(presentity, pres_uri, body, &presentity->etag,
1528
+						   rules_doc)
1529
+						< 0) {
1530
+				LM_ERR("while sending notify\n");
1531
+				goto error;
1532
+			}
1533
+			if(num_watchers == 0) {
1534
+				if(delete_presentity(presentity, &p_ruid) < 0) {
1535
+					LM_ERR("Deleting presentity\n");
1536
+					goto error;
1537
+				}
1538
+
1539
+				LM_DBG("deleted from db %.*s\n", presentity->user.len,
1540
+						presentity->user.s);
1541
+			}
1542
+			goto done;
1543
+		}
1544
+
1545
+		/* if event dialog and is_dialog -> if sender not the same as
1546
+		 * old sender do not overwrite */
1547
+		if(EVENT_DIALOG_SLA(presentity->event->evp)
1548
+				&& bla_update_publish == 0) {
1549
+			LM_DBG("drop Publish for BLA from a different sender that"
1550
+				   " wants to overwrite an existing dialog\n");
1551
+			LM_DBG("sender = %.*s\n", presentity->sender->len,
1552
+					presentity->sender->s);
1553
+			if(publ_send200ok(msg, presentity->expires, presentity->etag) < 0) {
1554
+				LM_ERR("sending 200OK reply\n");
1555
+				goto error;
1556
+			}
1557
+			if(sent_reply)
1558
+				*sent_reply = 1;
1559
+			goto done;
1560
+		}
1561
+
1562
+		if(presentity->event->etag_not_new == 0 || etag_override) {
1563
+			if(etag_override) {
1564
+				/* use the supplied etag */
1565
+				LM_DBG("updating with supplied etag %.*s\n", etag_override->len,
1566
+						etag_override->s);
1567
+				crt_etag = *etag_override;
1568
+				goto after_etag_generation;
1569
+			}
1570
+
1571
+			/* generate another etag */
1572
+			unsigned int publ_nr;
1573
+			str str_publ_nr = {0, 0};
1574
+
1575
+			dot = presentity->etag.s + presentity->etag.len;
1576
+			while(*dot != '.' && str_publ_nr.len < presentity->etag.len) {
1577
+				str_publ_nr.len++;
1578
+				dot--;
1579
+			}
1580
+			if(str_publ_nr.len == presentity->etag.len) {
1581
+				LM_ERR("wrong etag\n");
1582
+				goto error;
1583
+			}
1584
+			str_publ_nr.s = dot + 1;
1585
+			str_publ_nr.len--;
1586
+
1587
+			if(str2int(&str_publ_nr, &publ_nr) < 0) {
1588
+				LM_ERR("converting string to int\n");
1589
+				goto error;
1590
+			}
1591
+			etag.s = generate_ETag(publ_nr + 1);
1592
+			if(etag.s == NULL) {
1593
+				LM_ERR("while generating etag\n");
1594
+				goto error;
1595
+			}
1596
+			etag.len = (strlen(etag.s));
1597
+
1598
+			crt_etag = etag;
1599
+
1600
+after_etag_generation:
1601
+			ptc.etag = crt_etag;
1602
+		} else {
1603
+			crt_etag = presentity->etag;
1604
+		}
1605
+
1606
+		if(presentity->event->evp->type == EVENT_DIALOG) {
1607
+			if(ps_match_dialog_state(presentity, "terminated") == 1) {
1608
+				LM_WARN("Trying to update an already terminated state."
1609
+						" Skipping update.\n");
1610
+
1611
+				/* send 200OK */
1612
+				if(publ_send200ok(msg, presentity->expires, crt_etag) < 0) {
1613
+					LM_ERR("sending 200OK reply\n");
1614
+					goto error;
1615
+				}
1616
+				if(sent_reply) {
1617
+					*sent_reply = 1;
1618
+				}
1619
+				goto done;
1620
+			}
1621
+		}
1622
+
1623
+		ptc.expires = presentity->expires + (int)time(NULL);
1624
+		ptc.received_time = presentity->received_time;
1625
+		ptc.priority = presentity->priority;
1626
+		if(body && body->s) {
1627
+			ptc.body = *body;
1628
+		}
1629
+		if(presentity->sender) {
1630
+			ptc.sender = *presentity->sender;
1631
+		}
1632
+
1633
+		/* if there is no support for affected_rows and no previous query has been done,
1634
+		 * or dmq replication is enabled and we don't already know the ruid, do query */
1635
+		if((!cache_record_exists)
1636
+				|| (pres_enable_dmq > 0 && !p_ruid.s)) {
1637
+			ptx = ps_ptable_get_item(&ptc.user, &ptc.domain, &ptc.event,
1638
+					&ptc.etag);
1639
+			if(ptx == NULL) {
1640
+				goto send_412;
1641
+			}
1642
+			cache_record_exists = 1;
1643
+			affected_rows = 1;
1644
+			if(!p_ruid.s && ptx->ruid.s) {
1645
+				crt_ruid.len = ptx->ruid.len;
1646
+				crt_ruid.s = (char *)pkg_malloc(sizeof(char) * crt_ruid.len);
1647
+				if(!crt_ruid.s) {
1648
+					LM_ERR("no private memory\n");
1649
+					goto error;
1650
+				}
1651
+				memcpy(crt_ruid.s, ptx->ruid.s, crt_ruid.len);
1652
+				p_ruid = crt_ruid;
1653
+			}
1654
+			LM_DBG("existing ruid %.*s\n", p_ruid.len, p_ruid.s);
1655
+			ps_presentity_free(ptx, 1);
1656
+			ptx = NULL;
1657
+		}
1658
+		affected_rows = ps_ptable_update(&ptc);
1659
+		if(affected_rows < 0) {
1660
+			LM_ERR("updating published info in database\n");
1661
+			goto error;
1662
+		}
1663
+		affected_rows = 1;
1664
+		/* if either affected_rows (if exists) or select query show that there is no line in database*/
1665
+		if((!affected_rows && !cache_record_exists) || (!cache_record_exists)) {
1666
+			goto send_412;
1667
+		}
1668
+
1669
+		/* send 200OK */
1670
+		if(publ_send200ok(msg, presentity->expires, crt_etag) < 0) {
1671
+			LM_ERR("sending 200OK reply\n");
1672
+			goto error;
1673
+		}
1674
+		if(sent_reply) {
1675
+			*sent_reply = 1;
1676
+		}
1677
+
1678
+		if(!body) {
1679
+			goto done;
1680
+		}
1681
+	}
1682
+
1683
+send_notify:
1684
+
1685
+	/* send notify with presence information */
1686
+	if(publ_notify(presentity, pres_uri, body, NULL, rules_doc) < 0) {
1687
+		LM_ERR("while sending notify\n");
1688
+		goto error;
1689
+	}
1690
+
1691
+done:
1692
+
1693
+	if(pres_enable_dmq > 0 && p_ruid.s != NULL) {
1694
+		pres_dmq_replicate_presentity(
1695
+				presentity, body, new_t, &crt_etag, sphere, &p_ruid, NULL);
1696
+	}
1697
+
1698
+	if(etag.s) {
1699
+		pkg_free(etag.s);
1700
+	}
1701
+	etag.s = NULL;
1702
+
1703
+	if(crt_ruid.s) {
1704
+		pkg_free(crt_ruid.s);
1705
+	}
1706
+	crt_ruid.s = NULL;
1707
+
1708
+	if(rules_doc) {
1709
+		if(rules_doc->s) {
1710
+			pkg_free(rules_doc->s);
1711
+		}
1712
+		pkg_free(rules_doc);
1713
+		rules_doc = NULL;
1714
+	}
1715
+	if(pres_uri.s) {
1716
+		pkg_free(pres_uri.s);
1717
+		pres_uri.s = NULL;
1718
+	}
1719
+
1720
+	return 0;
1721
+
1722
+send_412:
1723
+
1724
+	if(!ruid) {
1725
+		LM_ERR("No E_Tag match %*s\n", presentity->etag.len,
1726
+				presentity->etag.s);
1727
+	} else {
1728
+		LM_ERR("No ruid match %*s\n", ruid->len, ruid->s);
1729
+	}
1730
+
1731
+	if(msg != NULL) {
1732
+		if(slb.freply(msg, 412, &pu_412_rpl) < 0) {
1733
+			LM_ERR("sending '412 Conditional request failed' reply\n");
1734
+			goto error;
1735
+		}
1736
+	}
1737
+	if(sent_reply) {
1738
+		*sent_reply = 1;
1739
+	}
1740
+	ret = 0;
1741
+
1742
+error:
1743
+	if(ptx) {
1744
+		ps_presentity_free(ptx, 1);
1745
+	}
1746
+	if(etag.s) {
1747
+		pkg_free(etag.s);
1748
+	}
1749
+	if(rules_doc) {
1750
+		if(rules_doc->s)
1751
+			pkg_free(rules_doc->s);
1752
+		pkg_free(rules_doc);
1753
+	}
1754
+	if(pres_uri.s) {
1755
+		pkg_free(pres_uri.s);
1756
+	}
1757
+	if(crt_ruid.s) {
1758
+		pkg_free(crt_ruid.s);
1759
+	}
1760
+
1761
+	return ret;
1762
+}
1763
+
1764
+/**
1765
+ *
1766
+ */
1767
+int update_presentity(sip_msg_t *msg, presentity_t *presentity, str *body,
1768
+		int new_t, int *sent_reply, char *sphere, str *etag_override, str *ruid,
1769
+		int replace)
1770
+{
1771
+	if(publ_cache_mode == PS_PCACHE_RECORD) {
1772
+		return ps_cache_update_presentity(msg, presentity, body, new_t,
1773
+				sent_reply, sphere, etag_override, ruid, replace);
1774
+	} else {
1775
+		return ps_db_update_presentity(msg, presentity, body, new_t,
1776
+				sent_reply, sphere, etag_override, ruid, replace);
1777
+	}
1778
+}
1779
+
1780
+/**
1781
+ *
1782
+ */
1297 1783
 int pres_htable_restore(void)
1298 1784
 {
1299 1785
 	/* query all records from presentity table and insert records
... ...
@@ -1742,7 +2228,10 @@ error:
1742 2228
 	return ret;
1743 2229
 }
1744 2230
 
1745
-int delete_presentity(presentity_t *pres, str *ruid)
2231
+/**
2232
+ *
2233
+ */
2234
+int ps_db_delete_presentity(presentity_t *pres, str *ruid)
1746 2235
 {
1747 2236
 	db_key_t query_cols[4];
1748 2237
 	db_val_t query_vals[4];
... ...
@@ -1799,6 +2288,39 @@ error:
1799 2288
 	return -1;
1800 2289
 }
1801 2290
 
2291
+/**
2292
+ *
2293
+ */
2294
+int ps_cache_delete_presentity(presentity_t *pres, str *ruid)
2295
+{
2296
+	ps_presentity_t ptc;
2297
+
2298
+	memset(&ptc, 0, sizeof(ps_presentity_t));
2299
+
2300
+	ptc.user = pres->user;
2301
+	ptc.domain = pres->domain;
2302
+	ptc.event = pres->event->name;
2303
+	ptc.etag = pres->etag;
2304
+
2305
+	if(ps_ptable_remove(&ptc) < 0) {
2306
+		return -1;
2307
+	}
2308
+
2309
+	return 0;
2310
+}
2311
+
2312
+/**
2313
+ *
2314
+ */
2315
+int delete_presentity(presentity_t *pres, str *ruid)
2316
+{
2317
+	if(publ_cache_mode == PS_PCACHE_RECORD) {
2318
+		return ps_cache_delete_presentity(pres, ruid);
2319
+	} else {
2320
+		return ps_db_delete_presentity(pres, ruid);
2321
+	}
2322
+}
2323
+
1802 2324
 int delete_offline_presentities(str *pres_uri, pres_ev_t *event)
1803 2325
 {
1804 2326
 	db_key_t query_cols[4];
... ...
@@ -247,6 +247,90 @@ error:
247 247
 	return;
248 248
 }
249 249
 
250
+/**
251
+ *
252
+ */
253
+void ps_ptable_timer_clean(unsigned int ticks, void *param)
254
+{
255
+	presentity_t pres;
256
+	ps_presentity_t *ptlist = NULL;
257
+	ps_presentity_t *ptn = NULL;
258
+	int eval = 0;
259
+	str uri = STR_NULL;
260
+	str *rules_doc = NULL;
261
+
262
+	eval = (int)time(NULL);
263
+	ptlist = ps_ptable_get_expired(eval);
264
+
265
+	if(ptlist==NULL) {
266
+		return;
267
+	}
268
+
269
+	for(ptn = ptlist; ptn != NULL; ptn = ptn->next) {
270
+		memset(&pres, 0, sizeof(presentity_t));
271
+
272
+		pres.user = ptn->user;
273
+		pres.domain = ptn->domain;
274
+		pres.etag = ptn->etag;
275
+		pres.event = contains_event(&ptn->event, NULL);
276
+		if(pres.event == NULL || pres.event->evp == NULL) {
277
+			LM_ERR("event not found\n");
278
+			goto error;
279
+		}
280
+
281
+		if(uandd_to_uri(pres.user, pres.domain, &uri) < 0) {
282
+			LM_ERR("constructing uri\n");
283
+			goto error;
284
+		}
285
+
286
+		LM_DBG("found expired publish for [user]=%.*s  [domanin]=%.*s\n",
287
+				pres.user.len, pres.user.s, pres.domain.len, pres.domain.s);
288
+
289
+		if(pres_force_delete == 1) {
290
+			if(ps_ptable_remove(ptn) <0) {
291
+				LM_ERR("Deleting presentity\n");
292
+				goto error;
293
+			}
294
+		} else {
295
+			if(pres.event->get_rules_doc
296
+					&& pres.event->get_rules_doc(
297
+								&pres.user, &pres.domain, &rules_doc)
298
+								< 0) {
299
+				LM_ERR("getting rules doc\n");
300
+				goto error;
301
+			}
302
+			if(publ_notify(&pres, uri, NULL, &pres.etag, rules_doc) < 0) {
303
+				LM_ERR("sending Notify request\n");
304
+				goto error;
305
+			}
306
+			if(rules_doc) {
307
+				if(rules_doc->s)
308
+					pkg_free(rules_doc->s);
309
+				pkg_free(rules_doc);
310
+				rules_doc = NULL;
311
+			}
312
+		}
313
+
314
+		pkg_free(uri.s);
315
+		uri.s = NULL;
316
+	}
317
+
318
+error:
319
+	if(ptlist != NULL) {
320
+		ps_presentity_list_free(ptlist, 1);
321
+	}
322
+	if(uri.s) {
323
+		pkg_free(uri.s);
324
+	}
325
+	if(rules_doc) {
326
+		if(rules_doc->s) {
327
+			pkg_free(rules_doc->s);
328
+		}
329
+		pkg_free(rules_doc);
330
+	}
331
+	return;
332
+}
333
+
250 334
 /**
251 335
  * PUBLISH request handling
252 336
  *
... ...
@@ -432,10 +516,9 @@ int ki_handle_publish_uri(struct sip_msg *msg, str *sender_uri)
432 516
 		goto error;
433 517
 	}
434 518
 
435
-	/* querry the database and update or insert */
436
-	if(update_presentity(msg, presentity, &body, etag_gen, &sent_reply, sphere,
437
-			   NULL, NULL, 0)
438
-			< 0) {
519
+	/* query the database and update or insert */
520
+	if(update_presentity(msg, presentity, &body, etag_gen, &sent_reply,
521
+			sphere, NULL, NULL, 0) < 0) {
439 522
 		LM_ERR("when updating presentity\n");
440 523
 		goto error;
441 524
 	}
... ...
@@ -588,4 +671,4 @@ done:
588 671
 	}
589 672
 
590 673
 	return ret;
591
-}
674
+}
592 675
\ No newline at end of file
... ...
@@ -43,6 +43,7 @@
43 43
 #include "../alias_db/alias_db.h"
44 44
 
45 45
 void msg_presentity_clean(unsigned int ticks, void *param);
46
+void ps_ptable_timer_clean(unsigned int ticks, void *param);
46 47
 
47 48
 int w_handle_publish(struct sip_msg *msg, char *str1, char *str2);
48 49
 int ki_handle_publish(sip_msg_t *msg);