/* (C) 2012-2022 by Harald Welte * * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include "config.h" #include #include #include #include /*! \brief retrieve SMPP command ID from a msgb */ uint32_t smpp_msgb_cmdid(struct msgb *msg) { uint8_t *tmp = msgb_data(msg) + 4; return ntohl(*(uint32_t *)tmp); } int smpp_determine_scheme(uint8_t dcs, uint8_t *data_coding, int *mode) { if ((dcs & 0xF0) == 0xF0) { if (dcs & 0x04) { /* bit 2 == 1: 8bit data */ *data_coding = 0x02; *mode = MODE_8BIT; } else { /* bit 2 == 0: default alphabet */ *data_coding = 0x01; *mode = MODE_7BIT; } } else if ((dcs & 0xE0) == 0) { switch (dcs & 0xC) { case 0: *data_coding = 0x01; *mode = MODE_7BIT; break; case 4: *data_coding = 0x02; *mode = MODE_8BIT; break; case 8: *data_coding = 0x08; /* UCS-2 */ *mode = MODE_8BIT; break; default: goto unknown_mo; } } else { unknown_mo: LOGP(DLSMS, LOGL_ERROR, "SMPP MO Unknown Data Coding 0x%02x\n", dcs); return -1; } return 0; } /* convert a 'struct tm' holding relative time to an absolute one by adding it to t_now */ static void relative2absolute(struct tm *tm, time_t t_now) { struct tm tm_now; localtime_r(&t_now, &tm_now); tm->tm_year += tm_now.tm_year; tm->tm_mon += tm_now.tm_mon; tm->tm_mday += tm_now.tm_mday; tm->tm_hour += tm_now.tm_hour; tm->tm_min += tm_now.tm_min; tm->tm_sec += tm_now.tm_sec; } #ifndef HAVE_TIMEGM /* for systems without a timegm() function, provide a reimplementation */ static time_t timegm(struct tm *tm) { const char *orig_tz = getenv("TZ"); time_t ret; setenv("TZ", "UTC", 1); ret = mktime(tm); if (orig_tz) setenv("TZ", orig_tz, 1); else unsetenv("TZ"); return ret; } #endif /*! Parse a SMPP time format as defined in SMPP v3.4 7.1.1. * \param[in] vp string containing the time as encoded in SMPP v3.4 * \param[in] t_now pointer to a time value for 'now'. Can be NULL, then we call time() ourselves. * \returns time_t value in seconds since the epoch of the absolute decoded time */ time_t smpp_parse_time_format(const char *vp, time_t *t_now) { unsigned int year, month, day, hour, minute, second, tenth, gmt_off_quarter; char plus_minus_relative; int gmt_off_minutes; struct tm tm; time_t ret; int rc; memset(&tm, 0, sizeof(tm)); if (vp[0] == '\0') return 0; /* YYMMDDhhmmsstnnp (where p can be -, + or R) */ rc = sscanf(vp, "%2u%2u%2u%2u%2u%2u%1u%2u%c", &year, &month, &day, &hour, &minute, &second, &tenth, &gmt_off_quarter, &plus_minus_relative); if (rc != 9) return (time_t) -1; tm.tm_year = year; /* month handling differs between absolute/relative below... */ tm.tm_mday = day; tm.tm_hour = hour; tm.tm_min = minute; tm.tm_sec = second; tm.tm_isdst = 0; switch (plus_minus_relative) { case '+': /* time is in quarter hours advanced compared to UTC */ if (year < 70) tm.tm_year += 100; tm.tm_mon = month - 1; gmt_off_minutes = 15 * gmt_off_quarter; tm.tm_min -= gmt_off_minutes; ret = timegm(&tm); break; case '-': /* time is in quarter hours retared compared to UTC */ if (year < 70) tm.tm_year += 100; tm.tm_mon = month - 1; gmt_off_minutes = 15 * gmt_off_quarter; tm.tm_min += gmt_off_minutes; ret = timegm(&tm); break; case 'R': /* relative time */ tm.tm_mon = month; if (t_now) relative2absolute(&tm, *t_now); else relative2absolute(&tm, time(NULL)); /* here we do want local time, as we're passing local time in above! */ ret = mktime(&tm); break; default: return (time_t) -1; } return ret; }