blob: bada972173f803f1e625666c5cb18971d559568f [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
Neels Hofmeyr6a8b9c72018-03-22 15:51:22 +010024#include <osmocom/core/logging.h>
Max5346f692022-07-28 14:19:22 +070025#include <osmocom/netif/stream.h>
26#include <osmocom/smpp/smpp_smsc.h>
27
28/*! \brief retrieve SMPP command ID from a msgb */
29uint32_t smpp_msgb_cmdid(struct msgb *msg)
30{
31 uint8_t *tmp = msgb_data(msg) + 4;
32 return ntohl(*(uint32_t *)tmp);
33}
Holger Hans Peter Freythera7328a52013-07-13 17:09:56 +020034
35int smpp_determine_scheme(uint8_t dcs, uint8_t *data_coding, int *mode)
36{
37 if ((dcs & 0xF0) == 0xF0) {
38 if (dcs & 0x04) {
39 /* bit 2 == 1: 8bit data */
40 *data_coding = 0x02;
41 *mode = MODE_8BIT;
42 } else {
43 /* bit 2 == 0: default alphabet */
44 *data_coding = 0x01;
45 *mode = MODE_7BIT;
46 }
47 } else if ((dcs & 0xE0) == 0) {
48 switch (dcs & 0xC) {
49 case 0:
50 *data_coding = 0x01;
51 *mode = MODE_7BIT;
52 break;
53 case 4:
54 *data_coding = 0x02;
55 *mode = MODE_8BIT;
56 break;
57 case 8:
58 *data_coding = 0x08; /* UCS-2 */
59 *mode = MODE_8BIT;
60 break;
61 default:
62 goto unknown_mo;
63 }
64 } else {
65unknown_mo:
66 LOGP(DLSMS, LOGL_ERROR, "SMPP MO Unknown Data Coding 0x%02x\n", dcs);
67 return -1;
68 }
69
70 return 0;
71
72}
Harald Weltee6f11602022-05-17 18:25:14 +020073
74/* convert a 'struct tm' holding relative time to an absolute one by adding it to t_now */
75static void relative2absolute(struct tm *tm, time_t t_now)
76{
77 struct tm tm_now;
78
79 localtime_r(&t_now, &tm_now);
80
81 tm->tm_year += tm_now.tm_year;
82 tm->tm_mon += tm_now.tm_mon;
83 tm->tm_mday += tm_now.tm_mday;
84 tm->tm_hour += tm_now.tm_hour;
85 tm->tm_min += tm_now.tm_min;
86 tm->tm_sec += tm_now.tm_sec;
87}
88
89#ifndef HAVE_TIMEGM
90/* for systems without a timegm() function, provide a reimplementation */
91static time_t timegm(struct tm *tm)
92{
93 const char *orig_tz = getenv("TZ");
94 time_t ret;
95
96 setenv("TZ", "UTC", 1);
97
98 ret = mktime(tm);
99
100 if (orig_tz)
101 setenv("TZ", orig_tz, 1);
102 else
103 unsetenv("TZ");
104
105 return ret;
106}
107#endif
108
109
110/*! Parse a SMPP time format as defined in SMPP v3.4 7.1.1.
111 * \param[in] vp string containing the time as encoded in SMPP v3.4
112 * \param[in] t_now pointer to a time value for 'now'. Can be NULL, then we call time() ourselves.
113 * \returns time_t value in seconds since the epoch of the absolute decoded time */
114time_t smpp_parse_time_format(const char *vp, time_t *t_now)
115{
116 unsigned int year, month, day, hour, minute, second, tenth, gmt_off_quarter;
117 char plus_minus_relative;
118 int gmt_off_minutes;
119 struct tm tm;
120 time_t ret;
121 int rc;
122
123 memset(&tm, 0, sizeof(tm));
124
125 if (vp[0] == '\0')
126 return 0;
127
128 /* YYMMDDhhmmsstnnp (where p can be -, + or R) */
129 rc = sscanf(vp, "%2u%2u%2u%2u%2u%2u%1u%2u%c", &year, &month, &day, &hour, &minute,
130 &second, &tenth, &gmt_off_quarter, &plus_minus_relative);
131 if (rc != 9)
132 return (time_t) -1;
133
134 tm.tm_year = year;
135 /* month handling differs between absolute/relative below... */
136 tm.tm_mday = day;
137 tm.tm_hour = hour;
138 tm.tm_min = minute;
139 tm.tm_sec = second;
140 tm.tm_isdst = 0;
141
142 switch (plus_minus_relative) {
143 case '+': /* time is in quarter hours advanced 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 '-': /* time is in quarter hours retared compared to UTC */
152 if (year < 70)
153 tm.tm_year += 100;
154 tm.tm_mon = month - 1;
155 gmt_off_minutes = 15 * gmt_off_quarter;
156 tm.tm_min += gmt_off_minutes;
157 ret = timegm(&tm);
158 break;
159 case 'R':
160 /* relative time */
161 tm.tm_mon = month;
162 if (t_now)
163 relative2absolute(&tm, *t_now);
164 else
165 relative2absolute(&tm, time(NULL));
166 /* here we do want local time, as we're passing local time in above! */
167 ret = mktime(&tm);
168 break;
169 default:
170 return (time_t) -1;
171 }
172
173 return ret;
174}