#ifdef XP_UNIX
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include "prthread.h"
#endif
#include <errno.h>
#include "../daemon/netsite.h"
#include "../public/nsapi.h"
#include <ucx/string.h>
#include <ucx/mempool.h>
#include "pblock.h"
#include "util.h"
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/evp.h>
static const unsigned char pr2six[
256] = {
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
62,
64,
64,
64,
63,
52,
53,
54,
55,
56,
57,
58,
59,
60,
61,
64,
64,
64,
64,
64,
64,
64,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
64,
64,
64,
64,
64,
64,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64,
64
};
size_t util_base64decode(
char *bufcoded,
size_t codedbytes,
char *bufout) {
register char *bufin = bufcoded;
register int nprbytes;
size_t nbytesdecoded;
nprbytes = (
int) codedbytes;
while(pr2six[(
int)(bufin[nprbytes-
1])] >=
64) {
nprbytes--;
}
nbytesdecoded = ((nprbytes+
3)/
4) *
3;
while (nprbytes >
0) {
*(bufout++) = (
unsigned char)
(pr2six[(
int)(*bufin)] <<
2 | pr2six[(
int)bufin[
1]] >>
4);
*(bufout++) = (
unsigned char)
(pr2six[(
int)bufin[
1]] <<
4 | pr2six[(
int)bufin[
2]] >>
2);
*(bufout++) = (
unsigned char)
(pr2six[(
int)bufin[
2]] <<
6 | pr2six[(
int)bufin[
3]]);
bufin +=
4;
nprbytes -=
4;
}
if(nprbytes &
03) {
if(pr2six[(
int)bufin[-
2]] >
63)
nbytesdecoded -=
2;
else
nbytesdecoded -=
1;
}
return nbytesdecoded;
}
char* util_base64encode(
char *in,
size_t len) {
BIO *b;
BIO *e;
BUF_MEM *mem;
e = BIO_new(BIO_f_base64());
b = BIO_new(BIO_s_mem());
BIO_set_flags(e,
BIO_FLAGS_BASE64_NO_NL);
e = BIO_push(e, b);
BIO_write(e, in, len);
BIO_flush(e);
BIO_get_mem_ptr(e, &mem);
char *out = malloc(mem->length +
1);
memcpy(out, mem->data, mem->length);
out[mem->length] =
'\0';
BIO_free_all(e);
return out;
}
NSAPI_PUBLIC char **util_env_create(
char **env,
int n,
int *pos)
{
int x;
if(!env) {
*pos =
0;
return (
char **)
MALLOC((n +
1)*
sizeof(
char *));
}
else {
for(x =
0; (env[x]); x++);
env = (
char **)
REALLOC(env, (n + x +
1)*(
sizeof(
char *)));
*pos = x;
return env;
}
}
NSAPI_PUBLIC void util_env_free(
char **env)
{
register char **ep = env;
for(ep = env; *ep; ep++)
FREE(*ep);
FREE(env);
}
NSAPI_PUBLIC char *util_env_str(
const char *name,
const char *value) {
char *t;
size_t len = strlen(name) + strlen(value) +
2;
t = (
char *)
MALLOC(len);
snprintf(t, len,
"%s=%s", name, value);
return t;
}
NSAPI_PUBLIC void util_env_replace(
char **env,
const char *name,
const char *value)
{
int x, y, z;
char *i;
for(x =
0; env[x]; x++) {
i = strchr(env[x],
'=');
*i =
'\0';
if(!strcmp(env[x], name)) {
y = strlen(env[x]);
z = strlen(value);
env[x] = (
char *)
REALLOC(env[x], y + z +
2);
util_sprintf(&env[x][y],
"=%s", value);
return;
}
*i =
'=';
}
}
NSAPI_PUBLIC char *util_sh_escape(
char *s)
{
char *ns = (
char *)
MALLOC(strlen(s) *
2 +
1);
register char *t, *u;
for(t = s, u = ns; *t; ++t, ++u) {
if(strchr(
"&;`''\"|*?~<>^()[]{}$\\ #!", *t))
*u++ =
'\\';
*u = *t;
}
*u =
'\0';
return ns;
}
NSAPI_PUBLIC char *util_env_find(
char **env,
const char *name)
{
char *i;
int x, r;
for(x =
0; env[x]; x++) {
i = strchr(env[x],
'=');
*i =
'\0';
r = !strcmp(env[x], name);
*i =
'=';
if(r)
return i +
1;
}
return NULL;
}
NSAPI_PUBLIC char **util_env_copy(
char **src,
char **dst)
{
char **src_ptr;
int src_cnt;
int index;
if (!src)
return NULL;
for (src_cnt =
0, src_ptr = src; *src_ptr; src_ptr++, src_cnt++);
if (!src_cnt)
return NULL;
dst = util_env_create(dst, src_cnt, &index);
for (src_ptr = src; *src_ptr; index++, src_ptr++)
dst[index] =
STRDUP(*src_ptr);
dst[index] =
NULL;
return dst;
}
NSAPI_PUBLIC int util_vsnprintf(
char *s,
int n,
register const char *fmt,
va_list args)
{
return vsnprintf(s, n, fmt, args);
}
NSAPI_PUBLIC int util_snprintf(
char *s,
int n,
const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
return vsnprintf(s, n, fmt, args);
}
NSAPI_PUBLIC int util_vsprintf(
char *s,
register const char *fmt, va_list args)
{
return vsprintf(s, fmt, args);
}
NSAPI_PUBLIC int util_sprintf(
char *s,
const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
return vsprintf(s, fmt, args);
}
NSAPI_PUBLIC void util_uri_unescape(
char *s)
{
char *t, *u;
for(t = s, u = s; *t; ++t, ++u) {
if((*t ==
'%') && t[
1] && t[
2]) {
*u = ((t[
1] >=
'A' ? ((t[
1] & 0xdf) -
'A')+
10 : (t[
1] -
'0'))*
16) +
(t[
2] >=
'A' ? ((t[
2] & 0xdf) -
'A')+
10 : (t[
2] -
'0'));
t +=
2;
}
else
if(u != t)
*u = *t;
}
*u = *t;
}
NSAPI_PUBLIC int util_uri_unescape_strict(
char *s)
{
char *t, *u, t1, t2;
int rv =
1;
for(t = s, u = s; *t; ++t, ++u) {
if (*t ==
'%') {
t1 = t[
1] & 0xdf;
if ((t1 <
'A' || t1 >
'F') && (t[
1] <
'0' || t[
1] >
'9'))
rv =
0;
t2 = t[
2] & 0xdf;
if ((t2 <
'A' || t2 >
'F') && (t[
2] <
'0' || t[
2] >
'9'))
rv =
0;
*u = ((t[
1] >=
'A' ? ((t[
1] & 0xdf) -
'A')+
10 : (t[
1] -
'0'))*
16) +
(t[
2] >=
'A' ? ((t[
2] & 0xdf) -
'A')+
10 : (t[
2] -
'0'));
t +=
2;
}
else if (u != t)
*u = *t;
}
*u = *t;
return rv;
}
NSAPI_PUBLIC int
util_uri_unescape_plus (
const char *src,
char *trg,
int len)
{
const char *t = src;
char *u = trg ==
NULL ? (
char *)src : trg;
int rlen =
0;
if (len == -
1)
len = strlen (src);
for( ; len && *t; ++t, ++u, len--, rlen++)
{
if((*t ==
'%') && t[
1] && t[
2])
{
*u = ((t[
1] >=
'A' ? ((t[
1] & 0xdf) -
'A') +
10 : (t[
1] -
'0')) *
16) +
(t[
2] >=
'A' ? ((t[
2] & 0xdf) -
'A') +
10 : (t[
2] -
'0'));
t +=
2;
len-=
2;
}
else
if (*t ==
'+')
*u =
' ';
else
*u = *t;
}
*u =
0;
return rlen;
}
NSAPI_PUBLIC int INTutil_getboolean(
const char *v,
int def) {
if(v[
0] ==
'T' || v[
0] ==
't') {
return 1;
}
if(v[
0] ==
'F' || v[
0] ==
'f') {
return 0;
}
return def;
}
int util_getboolean_s(
sstr_t s,
int def) {
if(s.length ==
0) {
return def;
}
if(s.ptr[
0] ==
'T' || s.ptr[
0] ==
't') {
return 1;
}
if(s.ptr[
0] ==
'F' || s.ptr[
0] ==
'f') {
return 0;
}
return def;
}
NSAPI_PUBLIC int util_strtoint(
char *str,
int64_t *value) {
char *end;
errno =
0;
int64_t val = strtoll(str, &end,
0);
if(errno ==
0) {
*value = val;
return 1;
}
else {
return 0;
}
}
NSAPI_PUBLIC int INTutil_itoa(
int i,
char *a) {
return INTutil_i64toa(i, a);
}
NSAPI_PUBLIC int INTutil_i64toa(
int64_t i,
char *a)
{
register int x, y, p;
register char c;
int negative;
negative =
0;
if(i <
0) {
*a++ =
'-';
negative =
1;
i = -i;
}
p =
0;
while(i >
9) {
a[p++] = (i%
10) +
'0';
i /=
10;
}
a[p++] = i +
'0';
if(p >
1) {
for(x =
0, y = p -
1; x < y; ++x, --y) {
c = a[x];
a[x] = a[y];
a[y] = c;
}
}
a[p] =
'\0';
return p + negative;
}
#ifndef XP_WIN32
NSAPI_PUBLIC struct passwd *
util_getpwnam(
const char *name,
struct passwd *result,
char *buffer,
int buflen)
{
struct passwd *rv;
errno = getpwnam_r(name, result, buffer, buflen, &rv);
if (errno !=
0)
rv =
NULL;
return rv;
}
#endif
#ifndef XP_WIN32
NSAPI_PUBLIC struct passwd *
util_getpwuid(
uid_t uid,
struct passwd *result,
char *buffer,
int buflen)
{
struct passwd *rv;
errno = getpwuid_r(uid, result, buffer, buflen, &rv);
if (errno !=
0)
rv =
NULL;
return rv;
}
#endif
NSAPI_PUBLIC int util_errno2status(
int errno_value) {
switch(errno_value) {
case 0: {
return 200;
}
case EACCES: {
return 403;
}
case ENOENT: {
return 404;
break;
}
}
return 500;
}
NSAPI_PUBLIC
sstr_t util_path_append(
pool_handle_t *pool,
char *path,
char *ch) {
sstr_t parent = sstr(path);
sstr_t child = sstr(ch);
sstr_t newstr;
UcxAllocator a = util_pool_allocator(pool);
if(parent.ptr[parent.length-
1] ==
'/') {
newstr = sstrcat_a(&a,
2, parent, child);
}
else {
newstr = sstrcat_a(&a,
3, parent,
S(
"/"), child);
}
return newstr;
}
sstr_t util_path_remove_last(
sstr_t path) {
int i;
for(i=path.length-
1;i>=
0;i--) {
char c = path.ptr[i];
if(c ==
'/') {
path.ptr[i] =
0;
path.length = i;
break;
}
}
if(i <
0) {
path.ptr =
NULL;
path.length =
0;
}
return path;
}
void util_add_ppath(
sstr_t root,
sstr_t path, pblock *vars) {
size_t length = root.length + path.length;
char *translated_path = alloca(length);
memcpy(translated_path, root.ptr, root.length);
memcpy(translated_path + root.length, path.ptr, path.length);
pblock_kvinsert(
pb_key_ppath,
translated_path,
length,
vars);
}
UcxAllocator util_pool_allocator(
pool_handle_t *pool) {
UcxAllocator a;
a.malloc = (ucx_allocator_malloc)pool_malloc;
a.calloc = (ucx_allocator_calloc)pool_calloc;
a.realloc = (ucx_allocator_realloc)pool_realloc;
a.free = (ucx_allocator_free)pool_free;
a.pool = pool;
return a;
}
NSAPI_PUBLIC pblock* util_parse_param(
pool_handle_t *pool,
char *query) {
pblock *pb = pblock_create_pool(pool,
32);
if(!pb) {
return NULL;
}
if(!query || !(*query)) {
return pb;
}
int loopFlag =
1;
int nl =
0;
int vl =
0;
int state =
0;
const char *np = query;
const char *vp =
NULL;
while (loopFlag) {
char delim = *query++;
switch (delim) {
case '&':
case '\0': {
if(!delim) {
loopFlag =
0;
}
state =
0;
if(nl >
0) {
util_uri_unescape_plus(np,
NULL, nl);
util_uri_unescape_plus(vp,
NULL, vl);
pblock_nvlinsert(np, nl, vp, vl, pb);
}
nl =
0;
vl =
0;
vp =
NULL;
np = query;
break;
}
case '=': {
state =
1;
vp = query;
break;
}
default: {
if(state) {
vl++;
}
else {
nl++;
}
}
}
}
return pb;
}
sstr_t sstrdup_mp(UcxMempool *pool,
sstr_t s) {
sstr_t newstring;
newstring.ptr = (
char*)ucx_mempool_malloc(pool, s.length +
1);
if (newstring.ptr !=
NULL) {
newstring.length = s.length;
newstring.ptr[newstring.length] =
0;
memcpy(newstring.ptr, s.ptr, s.length);
}
return newstring;
}
static const int MSTR2NUM_HT_MASK = 0xf;
struct mstr2num_ht {
unsigned ucmstr;
int mnum;
};
struct mstr2num_ht
MSTR2NUM_HT[] = {
{
'A' <<
16 |
'P' <<
8 |
'R',
3 },
{
'S' <<
16 |
'E' <<
8 |
'P',
8 },
{
'M' <<
16 |
'A' <<
8 |
'Y',
4 },
{
0, -
1 },
{
'M' <<
16 |
'A' <<
8 |
'R',
2 },
{
'F' <<
16 |
'E' <<
8 |
'B',
1 },
{
0, -
1 },
{
'D' <<
16 |
'E' <<
8 |
'C',
11 },
{
'O' <<
16 |
'C' <<
8 |
'T',
9 },
{
'J' <<
16 |
'U' <<
8 |
'N',
5 },
{
0, -
1 },
{
'A' <<
16 |
'U' <<
8 |
'G',
7 },
{
'J' <<
16 |
'A' <<
8 |
'N',
0 },
{
'J' <<
16 |
'U' <<
8 |
'L',
6 },
{
0, -
1 },
{
'N' <<
16 |
'O' <<
8 |
'V',
10 }
};
static inline
int _mstr2num(
const char *s)
{
const unsigned char *mstr = (
const unsigned char *) s;
unsigned char ucmstr0 = mstr[
0] & 0xdf;
unsigned ucmstr = ucmstr0 <<
16;
if (ucmstr0 !=
'\0') {
unsigned char ucmstr1 = mstr[
1] & 0xdf;
ucmstr |= ucmstr1 <<
8;
if (ucmstr1 !=
'\0') {
unsigned char ucmstr2 = mstr[
2] & 0xdf;
ucmstr |= ucmstr2;
unsigned hash = (ucmstr1 >>
2) ^ (ucmstr2 <<
1);
int i = hash &
MSTR2NUM_HT_MASK;
if (
MSTR2NUM_HT[i].ucmstr == ucmstr)
return MSTR2NUM_HT[i].mnum;
}
}
return -
1;
}
NSAPI_PUBLIC int util_mstr2num(
const char *s)
{
return _mstr2num(s);
}
static inline
const char * _parse_day_month(
const char *p,
int *day,
int *month)
{
*day =
0;
if (*p ==
',') {
p++;
if (*p ==
' ')
p++;
while (*p >=
'0' && *p <=
'9')
*day = *day *
10 + (*p++ -
'0');
if (*p ==
' ' || *p ==
'-')
p++;
*month = _mstr2num(p);
if (*month != -
1)
p +=
3;
}
else {
if (*p ==
' ')
p++;
*month = _mstr2num(p);
if (*month != -
1)
p +=
3;
while (*p ==
' ')
p++;
while (*p >=
'0' && *p <=
'9')
*day = *day *
10 + (*p++ -
'0');
}
return p;
}
static inline
void _parse_year_time(
const char *p,
int *year,
const char ** time)
{
int _year =
0;
if (*p ==
'-') {
p++;
while (*p >=
'0' && *p <=
'9')
_year = _year *
10 + (*p++ -
'0');
if (_year <
70) {
_year +=
2000;
}
else {
_year +=
1900;
}
if (*p ==
' ')
p++;
*time = p;
}
else {
if (*p ==
' ')
p++;
if (p[
0] && p[
1] && p[
2] ==
':') {
*time = p;
p +=
3;
while (*p && *p !=
' ')
p++;
if (*p ==
' ')
p++;
while (*p >=
'0' && *p <=
'9')
_year = _year *
10 + (*p++ -
'0');
}
else {
while (*p >=
'0' && *p <=
'9')
_year = _year *
10 + (*p++ -
'0');
if (*p ==
' ')
p++;
*time = p;
}
}
*year = _year;
}
NSAPI_PUBLIC int util_str_time_equal(
const char *t1,
const char *t2)
{
while (isspace(*t1))
t1++;
while (isalpha(*t1))
t1++;
while (isspace(*t2))
t2++;
while (isalpha(*t2))
t2++;
int day1;
int month1;
t1 = _parse_day_month(t1, &day1, &month1);
int day2;
int month2;
t2 = _parse_day_month(t2, &day2, &month2);
if (day1 != day2)
return -
1;
if (month1 != month2)
return -
1;
int year1;
const char *time1;
_parse_year_time(t1, &year1, &time1);
int year2;
const char *time2;
_parse_year_time(t2, &year2, &time2);
if (year1 != year2)
return -
1;
while (*time1 && *time1 !=
' ' && *time1 == *time2) {
time1++;
time2++;
}
if (*time2 && *time2 !=
' ')
return -
1;
return 0;
}
static int _time_compare(
const struct tm *lms,
const char *ims)
{
while (isspace(*ims))
ims++;
while (isalpha(*ims))
ims++;
int day;
int month;
ims = _parse_day_month(ims, &day, &month);
if (month == -
1)
return 1;
int year;
const char *time;
_parse_year_time(ims, &year, &time);
int rv;
rv = (lms->tm_year +
1900) - year;
if (rv)
return rv;
rv = lms->tm_mon - month;
if (rv)
return rv;
rv = lms->tm_mday - day;
if (rv)
return rv;
const char *p = time;
int hour =
0;
while (*p >=
'0' && *p <=
'9')
hour = hour *
10 + (*p++ -
'0');
if (*p ==
':')
p++;
rv = lms->tm_hour - hour;
if (rv)
return rv;
int minutes =
0;
while (*p >=
'0' && *p <=
'9')
minutes = minutes *
10 + (*p++ -
'0');
if (*p ==
':')
p++;
rv = lms->tm_min - minutes;
if (rv)
return rv;
int seconds =
0;
while (*p >=
'0' && *p <=
'9')
seconds = seconds *
10 + (*p++ -
'0');
if (*p ==
':')
p++;
rv = lms->tm_sec - seconds;
if (rv)
return rv;
return 0;
}
NSAPI_PUBLIC int util_later_than(
const struct tm *lms,
const char *ims)
{
return _time_compare(lms, ims) <=
0;
}
NSAPI_PUBLIC int util_time_equal(
const struct tm *lms,
const char *ims)
{
return _time_compare(lms, ims) ==
0;
}
NSAPI_PUBLIC struct tm *
util_gmtime(
const time_t *clock,
struct tm *res)
{
return gmtime_r(clock, res);
}
int util_isdate(
char *str) {
sstr_t datestr = sstr(str);
sstr_t example =
S(
"Sun, 06 Nov 1994 08:49:37 GMT");
if(datestr.length != example.length) {
return 0;
}
for(
int i=
0;i<datestr.length;i++) {
char e = example.ptr[i];
if(isdigit(e)) {
if(!isdigit(datestr.ptr[i])) {
return 0;
}
}
else if(e ==
' ') {
if(datestr.ptr[i] !=
' ') {
return 0;
}
}
else if(e ==
',') {
if(datestr.ptr[i] !=
',') {
return 0;
}
}
else if(e ==
':') {
if(datestr.ptr[i] !=
':') {
return 0;
}
}
}
if(!sstrsuffix(datestr,
S(
"GMT"))) {
return 0;
}
return 1;
}
NSAPI_PUBLIC int util_mime_separator(
char *sep)
{
int size =
35;
int pos =
0;
sep[pos++] =
CR;
sep[pos++] =
LF;
sep[pos++] =
'-';
sep[pos++] =
'-';
int r[
6];
for(
int i=
0;i<
6;i++) {
r[i] = rand() %
10000;
}
pos += snprintf(
sep+
4,
size-
4,
"X%04x%04x%04x%04x%04x%04xE",
r[
0],
r[
1],
r[
2],
r[
3],
r[
4],
r[
5]);
return pos;
}