From 694adf71986658cdf3c6924cb7605859e5756171 Mon Sep 17 00:00:00 2001
From: Alexander Chemeris <Alexander.Chemeris@gmail.com>
Date: Tue, 26 Nov 2013 15:04:48 -0600
Subject: [PATCH] libmsc,sms: Properly calculate and store validity and
 received timestamps for incoming SMS.

---
 openbsc/include/openbsc/gsm_data.h |    3 ++-
 openbsc/src/libmsc/db.c            |   24 +++++++++++++++---------
 openbsc/src/libmsc/gsm_04_11.c     |    8 +++++++-
 openbsc/tests/db/db_test.c         |    5 +++++
 4 files changed, 29 insertions(+), 11 deletions(-)

diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index e6a94ad..2ce7727 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -315,7 +315,8 @@ struct gsm_sms {
 		char msg_id[16];
 	} smpp;
 
-	unsigned long validity_minutes;
+	time_t received_time;
+	time_t valid_until;
 	uint8_t reply_path_req;
 	uint8_t status_rep_req;
 	uint8_t ud_hdr_ind;
diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c
index 3b92691..60b39df 100644
--- a/openbsc/src/libmsc/db.c
+++ b/openbsc/src/libmsc/db.c
@@ -2,6 +2,7 @@
 /* (C) 2008 by Jan Luebbe <jluebbe@debian.org>
  * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
  * (C) 2009 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2014 by Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
  * All Rights Reserved
  *
  * This program is free software; you can redistribute it and/or modify
@@ -113,6 +114,7 @@ static const char *create_stmts[] = {
 		/* metadata, not part of sms */
 		"id INTEGER PRIMARY KEY AUTOINCREMENT, "
 		"created TIMESTAMP NOT NULL, "
+		"received TIMESTAMP, "
 		"sent TIMESTAMP, "
 		"deliver_attempts INTEGER NOT NULL DEFAULT 0, "
 		/* data directly copied/derived from SMS */
@@ -245,6 +247,8 @@ static struct gsm_sms *sms_from_result_v3(dbi_result result)
 	sms->protocol_id = dbi_result_get_uint(result, "protocol_id");
 	sms->data_coding_scheme = dbi_result_get_uint(result,
 						  "data_coding_scheme");
+	sms->received_time = dbi_result_get_datetime(result, "created");
+	sms->valid_until = dbi_result_get_datetime(result, "valid_until");
 
 	daddr = dbi_result_get_string(result, "dest_addr");
 	if (daddr) {
@@ -1276,32 +1280,33 @@ int db_sms_store(struct gsm_sms *sms)
 	dbi_result result;
 	char *q_text, *q_daddr, *q_saddr;
 	unsigned char *q_udata;
-	char *validity_timestamp = "2222-2-2";
-
-	/* FIXME: generate validity timestamp based on validity_minutes */
+	char received_timestamp[22];
+	char validity_timestamp[22];
 
 	dbi_conn_quote_string_copy(conn, (char *)sms->text, &q_text);
 	dbi_conn_quote_string_copy(conn, (char *)sms->dst.addr, &q_daddr);
 	dbi_conn_quote_string_copy(conn, (char *)sms->src.addr, &q_saddr);
 	dbi_conn_quote_binary_copy(conn, sms->user_data, sms->user_data_len,
 				   &q_udata);
-
-	/* FIXME: correct validity period */
+	strftime(received_timestamp, sizeof(received_timestamp),
+			 "'%F %T'", gmtime(&sms->received_time));
+	strftime(validity_timestamp, sizeof(validity_timestamp),
+			 "'%F %T'", gmtime(&sms->valid_until));
 	result = dbi_conn_queryf(conn,
 		"INSERT INTO SMS "
-		"(created, valid_until, "
+		"(created, received, valid_until, "
 		 "reply_path_req, status_rep_req, protocol_id, "
 		 "data_coding_scheme, ud_hdr_ind, "
 		 "user_data, text, "
 		 "dest_addr, dest_ton, dest_npi, "
 		 "src_addr, src_ton, src_npi) VALUES "
-		"(datetime('now'), %u, "
+		"(datetime('now'), %s, %s, "
 		"%u, %u, %u, "
 		"%u, %u, "
 		"%s, %s, "
 		"%s, %u, %u, "
 		"%s, %u, %u)",
-		validity_timestamp,
+		received_timestamp, validity_timestamp,
 		sms->reply_path_req, sms->status_rep_req, sms->protocol_id,
 		sms->data_coding_scheme, sms->ud_hdr_ind,
 		q_udata, q_text,
@@ -1330,7 +1335,6 @@ static struct gsm_sms *sms_from_result(struct gsm_network *net, dbi_result resul
 
 	sms->id = dbi_result_get_ulonglong(result, "id");
 
-	/* FIXME: validity */
 	/* FIXME: those should all be get_uchar, but sqlite3 is braindead */
 	sms->reply_path_req = dbi_result_get_uint(result, "reply_path_req");
 	sms->status_rep_req = dbi_result_get_uint(result, "status_rep_req");
@@ -1338,6 +1342,8 @@ static struct gsm_sms *sms_from_result(struct gsm_network *net, dbi_result resul
 	sms->protocol_id = dbi_result_get_uint(result, "protocol_id");
 	sms->data_coding_scheme = dbi_result_get_uint(result,
 						  "data_coding_scheme");
+	sms->received_time = dbi_result_get_datetime(result, "received");
+	sms->valid_until = dbi_result_get_datetime(result, "valid_until");
 	/* sms->msg_ref is temporary and not stored in DB */
 
 	sms->dst.npi = dbi_result_get_uint(result, "dest_npi");
diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c
index 566feb9..762dc73 100644
--- a/openbsc/src/libmsc/gsm_04_11.c
+++ b/openbsc/src/libmsc/gsm_04_11.c
@@ -102,6 +102,10 @@ struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver,
 	sms->protocol_id = 0; /* implicit */
 	sms->data_coding_scheme = dcs;
 	strncpy(sms->dst.addr, receiver->extension, sizeof(sms->dst.addr)-1);
+	/* Timestamps */
+	time(&sms->received_time);
+	time(&sms->valid_until);
+	sms->valid_until += SMS_DEFAULT_VALIDITY_PERIOD;
 	/* Generate user_data */
 	sms->user_data_len = gsm_7bit_encode_n(sms->user_data, sizeof(sms->user_data),
 						sms->text, NULL);
@@ -384,7 +388,9 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m
 			sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
 				osmo_hexdump(gsms->user_data, gsms->user_data_len));
 
-	gsms->validity_minutes = gsm340_validity_period(sms_vpf, sms_vp);
+	gsms->received_time = time(NULL);
+	gsms->valid_until = gsm340_validity_period(gsms->received_time,
+		sms_vpf, sms_vp);
 
 	/* FIXME: This looks very wrong */
 	send_signal(0, NULL, gsms, 0);
diff --git a/openbsc/tests/db/db_test.c b/openbsc/tests/db/db_test.c
index ba3fdfb..039b152 100644
--- a/openbsc/tests/db/db_test.c
+++ b/openbsc/tests/db/db_test.c
@@ -73,6 +73,9 @@ static void test_sms(void)
 	sms = sms_alloc();
 	sms->receiver = subscr_get(subscr);
 
+	sms->received_time = 12345;
+	sms->valid_until = 67890;
+
 	sms->src.ton = 0x23;
 	sms->src.npi = 0x24;
 	memcpy(sms->src.addr, "1234", strlen("1234") + 1);
@@ -100,6 +103,8 @@ static void test_sms(void)
 	sms = db_sms_get_unsent_for_subscr(subscr);
 	OSMO_ASSERT(sms);
 	OSMO_ASSERT(sms->receiver == subscr);
+	OSMO_ASSERT(sms->received_time == 12345);
+	OSMO_ASSERT(sms->valid_until == 67890);
 	OSMO_ASSERT(sms->reply_path_req == 1);
 	OSMO_ASSERT(sms->status_rep_req == 2);
 	OSMO_ASSERT(sms->ud_hdr_ind == 3);
-- 
1.7.9.5

