blob: 3c7757b9a49fc066f6dde8eb1df96989eba2d301 [file] [log] [blame]
Holger Hans Peter Freythera7328a52013-07-13 17:09:56 +02001
Harald Weltee6f11602022-05-17 18:25:14 +02002/* (C) 2012-2022 by Harald Welte <laforge@gnumonks.org>
Holger Hans Peter Freythera7328a52013-07-13 17:09:56 +02003 *
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
Harald Weltee6f11602022-05-17 18:25:14 +020020#include "config.h"
21
22#include <time.h>
Holger Hans Peter Freythera7328a52013-07-13 17:09:56 +020023
24#include "smpp_smsc.h"
Neels Hofmeyr6a8b9c72018-03-22 15:51:22 +010025#include <osmocom/core/logging.h>
Holger Hans Peter Freythera7328a52013-07-13 17:09:56 +020026
27int smpp_determine_scheme(uint8_t dcs, uint8_t *data_coding, int *mode)
28{
29 if ((dcs & 0xF0) == 0xF0) {
30 if (dcs & 0x04) {
31 /* bit 2 == 1: 8bit data */
32 *data_coding = 0x02;
33 *mode = MODE_8BIT;
34 } else {
35 /* bit 2 == 0: default alphabet */
36 *data_coding = 0x01;
37 *mode = MODE_7BIT;
38 }
39 } else if ((dcs & 0xE0) == 0) {
40 switch (dcs & 0xC) {
41 case 0:
42 *data_coding = 0x01;
43 *mode = MODE_7BIT;
44 break;
45 case 4:
46 *data_coding = 0x02;
47 *mode = MODE_8BIT;
48 break;
49 case 8:
50 *data_coding = 0x08; /* UCS-2 */
51 *mode = MODE_8BIT;
52 break;
53 default:
54 goto unknown_mo;
55 }
56 } else {
57unknown_mo:
58 LOGP(DLSMS, LOGL_ERROR, "SMPP MO Unknown Data Coding 0x%02x\n", dcs);
59 return -1;
60 }
61
62 return 0;
63
64}
Harald Weltee6f11602022-05-17 18:25:14 +020065
66/* convert a 'struct tm' holding relative time to an absolute one by adding it to t_now */
67static void relative2absolute(struct tm *tm, time_t t_now)
68{
69 struct tm tm_now;
70
71 localtime_r(&t_now, &tm_now);
72
73 tm->tm_year += tm_now.tm_year;
74 tm->tm_mon += tm_now.tm_mon;
75 tm->tm_mday += tm_now.tm_mday;
76 tm->tm_hour += tm_now.tm_hour;
77 tm->tm_min += tm_now.tm_min;
78 tm->tm_sec += tm_now.tm_sec;
79}
80
81#ifndef HAVE_TIMEGM
82/* for systems without a timegm() function, provide a reimplementation */
83static time_t timegm(struct tm *tm)
84{
85 const char *orig_tz = getenv("TZ");
86 time_t ret;
87
88 setenv("TZ", "UTC", 1);
89
90 ret = mktime(tm);
91
92 if (orig_tz)
93 setenv("TZ", orig_tz, 1);
94 else
95 unsetenv("TZ");
96
97 return ret;
98}
99#endif
100
101
102/*! Parse a SMPP time format as defined in SMPP v3.4 7.1.1.
103 * \param[in] vp string containing the time as encoded in SMPP v3.4
104 * \param[in] t_now pointer to a time value for 'now'. Can be NULL, then we call time() ourselves.
105 * \returns time_t value in seconds since the epoch of the absolute decoded time */
106time_t smpp_parse_time_format(const char *vp, time_t *t_now)
107{
108 unsigned int year, month, day, hour, minute, second, tenth, gmt_off_quarter;
109 char plus_minus_relative;
110 int gmt_off_minutes;
111 struct tm tm;
112 time_t ret;
113 int rc;
114
115 memset(&tm, 0, sizeof(tm));
116
117 if (vp[0] == '\0')
118 return 0;
119
120 /* YYMMDDhhmmsstnnp (where p can be -, + or R) */
121 rc = sscanf(vp, "%2u%2u%2u%2u%2u%2u%1u%2u%c", &year, &month, &day, &hour, &minute,
122 &second, &tenth, &gmt_off_quarter, &plus_minus_relative);
123 if (rc != 9)
124 return (time_t) -1;
125
126 tm.tm_year = year;
127 /* month handling differs between absolute/relative below... */
128 tm.tm_mday = day;
129 tm.tm_hour = hour;
130 tm.tm_min = minute;
131 tm.tm_sec = second;
132 tm.tm_isdst = 0;
133
134 switch (plus_minus_relative) {
135 case '+': /* time is in quarter hours advanced compared to UTC */
136 if (year < 70)
137 tm.tm_year += 100;
138 tm.tm_mon = month - 1;
139 gmt_off_minutes = 15 * gmt_off_quarter;
140 tm.tm_min -= gmt_off_minutes;
141 ret = timegm(&tm);
142 break;
143 case '-': /* time is in quarter hours retared compared to UTC */
144 if (year < 70)
145 tm.tm_year += 100;
146 tm.tm_mon = month - 1;
147 gmt_off_minutes = 15 * gmt_off_quarter;
148 tm.tm_min += gmt_off_minutes;
149 ret = timegm(&tm);
150 break;
151 case 'R':
152 /* relative time */
153 tm.tm_mon = month;
154 if (t_now)
155 relative2absolute(&tm, *t_now);
156 else
157 relative2absolute(&tm, time(NULL));
158 /* here we do want local time, as we're passing local time in above! */
159 ret = mktime(&tm);
160 break;
161 default:
162 return (time_t) -1;
163 }
164
165 return ret;
166}