Merge branch 'master' of pc18:/srv/git/r/doldaconnect
[doldaconnect.git] / common / utils.c
CommitLineData
d3372da9 1/*
2 * Dolda Connect - Modular multiuser Direct Connect-style client
302a2600 3 * Copyright (C) 2004 Fredrik Tolf <fredrik@dolda2000.com>
d3372da9 4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18*/
b5010caa 19#include <stdlib.h>
d3372da9 20#include <stdarg.h>
21#include <stdio.h>
22#include <wchar.h>
23#include <iconv.h>
24#include <errno.h>
25#include <string.h>
26#include <wctype.h>
27#include <langinfo.h>
28#include <pwd.h>
29#include <unistd.h>
30#include <sys/time.h>
31#include <netinet/in.h>
e304af88 32#include <alloca.h>
d3372da9 33
34#ifdef HAVE_CONFIG_H
35#include <config.h>
36#endif
8b17e919 37#include <utils.h>
38#include <log.h>
d3372da9 39
40static char *base64set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
41static int base64rev[] = {
42 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
43 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
44 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
45 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
46 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
47 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
48 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
49 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
50 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
51 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
52 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
53 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
54 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
55 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
56 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
57 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
58};
59static char *base32set = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
60static int base32rev[] = {
61 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
62 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
63 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
64 -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1,
65 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
66 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
67 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
68 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
69 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
70 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
71 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
72 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
73 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
74 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
75 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
76 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
77};
78
79char *vsprintf2(char *format, va_list al)
80{
81 int ret;
82 char *buf;
4dffb251 83 va_list al2;
d3372da9 84
4dffb251 85 va_copy(al2, al);
fe8c6c8e 86 ret = vsnprintf(NULL, 0, format, al2);
87 va_end(al2);
d3372da9 88 if((buf = malloc(ret + 1)) == NULL)
89 {
90 LOGOOM(ret + 1);
91 return(NULL);
92 }
4dffb251 93 va_copy(al2, al);
fe8c6c8e 94 vsnprintf(buf, ret + 1, format, al2);
95 va_end(al2);
d3372da9 96 return(buf);
97}
98
99char *sprintf2(char *format, ...)
100{
101 va_list args;
102 char *buf;
103
104 va_start(args, format);
105 buf = vsprintf2(format, args);
106 va_end(args);
107 return(buf);
108}
109
110wchar_t *vswprintf2(wchar_t *format, va_list al)
111{
112 int ret;
113 wchar_t *buf;
114 size_t bufsize;
4dffb251 115 va_list al2;
d3372da9 116
117 buf = smalloc(sizeof(wchar_t) * (bufsize = 1024));
4dffb251 118 while(1)
119 {
120 va_copy(al2, al);
121 ret = vswprintf(buf, bufsize, format, al2);
fe8c6c8e 122 va_end(al2);
4dffb251 123 if(ret >= 0)
124 break;
d3372da9 125 buf = srealloc(buf, sizeof(wchar_t) * (bufsize *= 2));
4dffb251 126 }
d3372da9 127 if(bufsize > ret + 1)
128 buf = srealloc(buf, sizeof(wchar_t) * (ret + 1));
129 return(buf);
130}
131
132wchar_t *swprintf2(wchar_t *format, ...)
133{
134 va_list args;
135 wchar_t *buf;
136
137 va_start(args, format);
138 buf = vswprintf2(format, args);
139 va_end(args);
140 return(buf);
141}
142
edccab15 143int havecharset(char *charset)
144{
145 iconv_t cd;
146
147 if((cd = iconv_open("wchar_t", charset)) == (iconv_t)-1)
148 return(0);
149 iconv_close(cd);
150 if((cd = iconv_open(charset, "wchar_t")) == (iconv_t)-1)
151 return(0);
152 iconv_close(cd);
153 return(1);
154}
155
d3372da9 156wchar_t *icmbstowcs(char *mbs, char *charset)
157{
158 int ret;
159 char *buf;
160 char *p, *p2;
161 size_t len1, len2, bufsize, data;
162 iconv_t cd;
163
164 len1 = strlen(mbs) + 1;
165 bufsize = len2 = len1 * sizeof(wchar_t);
166 if((buf = malloc(bufsize)) == NULL)
167 {
168 LOGOOM(bufsize);
169 return(NULL);
170 }
171 if(charset == NULL)
172 charset = nl_langinfo(CODESET);
173 if((cd = iconv_open("wchar_t", charset)) == (iconv_t)-1)
174 {
8b17e919 175#ifdef DAEMON
d3372da9 176 flog(LOG_ERR, "icmbstowcs: could not open iconv structure for %s: %s", charset, strerror(errno));
8b17e919 177#endif
d3372da9 178 free(buf);
179 return(NULL);
180 }
181 p = buf;
182 while(len1 > 0)
183 {
184 ret = iconv(cd, &mbs, &len1, &p, &len2);
185 if(ret < 0)
186 {
187 if(errno == E2BIG)
188 {
189 data = p - buf;
190 len2 += 128;
191 bufsize += 128;
192 if((p2 = realloc(buf, bufsize)) == NULL)
193 {
194 LOGOOM(bufsize);
195 free(buf);
196 iconv_close(cd);
197 return(NULL);
198 }
199 buf = p2;
200 p = buf + data;
201 } else {
202 free(buf);
203 iconv_close(cd);
204 return(NULL);
205 }
206 }
207 }
208 if(len2 > 0)
209 buf = realloc(buf, p - buf);
210 iconv_close(cd);
211 return((wchar_t *)buf);
212}
213
214wchar_t *icsmbstowcs(char *mbs, char *charset, wchar_t *def)
215{
216 static wchar_t *buf = NULL;
217
218 if(buf != NULL)
219 free(buf);
220 if((buf = icmbstowcs(mbs, charset)) == NULL)
221 {
96cf7d1f 222 if((def != NULL) && (*def == L'~'))
d3372da9 223 {
8b17e919 224#ifdef DAEMON
d3372da9 225 flog(LOG_WARNING, "icsmbstowcs: could not convert wcs string into charset %s: %s", charset, strerror(errno));
8b17e919 226#endif
d3372da9 227 def++;
228 }
229 return(def);
230 }
231 return(buf);
232}
233
234char *icwcstombs(wchar_t *wcs, char *charset)
235{
236 int ret;
237 char *buf;
238 char *p, *p2;
239 size_t len1, len2, bufsize, data;
240 iconv_t cd;
241
242 len1 = sizeof(wchar_t) * (wcslen(wcs) + 1);
243 bufsize = len2 = len1;
244 if((buf = malloc(bufsize)) == NULL)
245 {
8b17e919 246#ifdef DAEMON
d3372da9 247 LOGOOM(bufsize);
8b17e919 248#endif
d3372da9 249 return(NULL);
250 }
251 if(charset == NULL)
252 charset = nl_langinfo(CODESET);
253 if((cd = iconv_open(charset, "wchar_t")) == (iconv_t)-1)
254 {
8b17e919 255#ifdef DAEMON
d3372da9 256 flog(LOG_ERR, "icwcstombs: could not open iconv structure for %s: %s", charset, strerror(errno));
8b17e919 257#endif
d3372da9 258 free(buf);
259 return(NULL);
260 }
261 p = buf;
262 while(len1 > 0)
263 {
264 ret = iconv(cd, (char **)&wcs, &len1, &p, &len2);
265 if(ret < 0)
266 {
267 if(errno == E2BIG)
268 {
269 data = p - buf;
270 len2 += 128;
271 bufsize += 128;
272 if((p2 = realloc(buf, bufsize)) == NULL)
273 {
274 LOGOOM(bufsize);
275 free(buf);
276 iconv_close(cd);
277 return(NULL);
278 }
279 buf = p2;
280 p = buf + data;
281 } else {
282 free(buf);
283 iconv_close(cd);
284 return(NULL);
285 }
286 }
287 }
288 if(len2 > 0)
289 buf = realloc(buf, p - buf);
290 iconv_close(cd);
291 return(buf);
292}
293
294char *icswcstombs(wchar_t *wcs, char *charset, char *def)
295{
296 static char *buf = NULL;
297
298 if(buf != NULL)
299 free(buf);
300 if((buf = icwcstombs(wcs, charset)) == NULL)
301 {
96cf7d1f 302 if((def != NULL) && (*def == '~'))
d3372da9 303 {
8b17e919 304#ifdef DAEMON
d3372da9 305 flog(LOG_WARNING, "icswcstombs: could not convert mbs string from charset %s: %s", charset, strerror(errno));
8b17e919 306#endif
d3372da9 307 def++;
308 }
309 return(def);
310 }
311 return(buf);
312}
313
314wchar_t *wcstolower(wchar_t *wcs)
315{
316 wchar_t *p;
317
318 for(p = wcs; *p != L'\0'; p++)
319 *p = towlower(*p);
320 return(wcs);
321}
322
323wchar_t ucptowc(int ucp)
324{
325 int ret;
326 unsigned long ucpbuf;
327 char *buf;
328 char *mbsp, *p, *p2;
329 wchar_t res;
330 size_t len1, len2, bufsize, data;
331 iconv_t cd;
332
333 ucpbuf = htonl(ucp);
334 mbsp = (char *)&ucpbuf;
335 len1 = 4;
336 bufsize = len2 = len1 * sizeof(wchar_t);
337 if((buf = malloc(bufsize)) == NULL)
338 {
339 LOGOOM(bufsize);
340 return(L'\0');
341 }
342 if((cd = iconv_open("wchar_t", "UCS-4BE")) == (iconv_t)-1)
343 {
8b17e919 344#ifdef DAEMON
d3372da9 345 flog(LOG_ERR, "ucptowc: could not open iconv structure for UCS-4BE: %s", strerror(errno));
8b17e919 346#endif
d3372da9 347 free(buf);
348 return(L'\0');
349 }
350 p = buf;
351 while(len1 > 0)
352 {
353 ret = iconv(cd, &mbsp, &len1, &p, &len2);
354 if(ret < 0)
355 {
356 if(errno == E2BIG)
357 {
358 data = p - buf;
359 len2 += 128;
360 bufsize += 128;
361 if((p2 = realloc(buf, bufsize)) == NULL)
362 {
363 LOGOOM(bufsize);
364 free(buf);
365 iconv_close(cd);
366 return(L'\0');
367 }
368 buf = p2;
369 p = buf + data;
370 } else {
371 free(buf);
372 iconv_close(cd);
373 return(L'\0');
374 }
375 }
376 }
377 if(len2 > 0)
378 buf = realloc(buf, p - buf);
379 iconv_close(cd);
380 res = *(wchar_t *)buf;
381 free(buf);
382 return(res);
383}
384
385void _sizebuf(void **buf, size_t *bufsize, size_t reqsize, size_t elsize, int algo)
386{
387 if(*bufsize >= reqsize)
388 return;
389 switch(algo)
390 {
391 case 0:
392 *buf = srealloc(*buf, elsize * ((*bufsize) = reqsize));
393 break;
394 case 1:
395 if(*bufsize == 0)
396 *bufsize = 1;
397 while(*bufsize < reqsize)
398 *bufsize <<= 1;
399 *buf = srealloc(*buf, elsize * (*bufsize));
400 break;
401 }
402}
403
404double ntime(void)
405{
406 struct timeval tv;
407
408 gettimeofday(&tv, NULL);
409 return((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
410}
411
412int wcsexists(wchar_t *h, wchar_t *n)
413{
414 int i, o, nl, hl;
415 wchar_t *ln, *lh;
416
417 ln = alloca(sizeof(*ln) * (nl = wcslen(n)));
418 for(i = 0; i < nl; i++)
419 ln[i] = towlower(n[i]);
420 lh = alloca(sizeof(*lh) * (hl = wcslen(h)));
421 if(nl > hl)
422 return(0);
423 for(i = 0; i < nl; i++)
424 lh[i] = towlower(h[i]);
425 i = 0;
426 while(1)
427 {
428 for(o = 0; o < nl; o++)
429 {
430 if(lh[i + o] != ln[o])
431 break;
432 }
433 if(o == nl)
434 return(1);
435 if(i == hl - nl)
436 return(0);
437 lh[i + nl] = towlower(h[i + nl]);
438 i++;
439 }
440}
441
442#ifndef HAVE_WCSCASECMP
443int wcscasecmp(const wchar_t *s1, const wchar_t *s2)
444{
2b1082a6 445 for(; (towlower(*s1) == towlower(*s2)) && (*s1 != L'\0'); s1++, s2++);
d3372da9 446 return(towlower(*s1) - towlower(*s2));
447}
448#endif
449
450char *hexencode(char *data, size_t datalen)
451{
452 char *buf, this;
453 size_t bufsize, bufdata;
454 int dig;
455
456 buf = NULL;
457 bufsize = bufdata = 0;
458 for(; datalen > 0; datalen--, data++)
459 {
460 dig = (*data & 0xF0) >> 4;
461 if(dig > 9)
462 this = 'A' + dig - 10;
463 else
464 this = dig + '0';
465 addtobuf(buf, this);
466 dig = *data & 0x0F;
467 if(dig > 9)
468 this = 'A' + dig - 10;
469 else
470 this = dig + '0';
471 addtobuf(buf, this);
472 }
473 addtobuf(buf, 0);
474 return(buf);
475}
476
477char *hexdecode(char *data, size_t *len)
478{
b9707562 479 char *buf, this, bit;
d3372da9 480 size_t bufsize, bufdata;
481
482 buf = NULL;
483 bufsize = bufdata = 0;
b9707562 484 for(bit = 4, this = 0; *data; data++)
d3372da9 485 {
486 if((*data >= 'A') && (*data <= 'F'))
487 {
b9707562 488 this |= (this & 0x0F) | ((*data - 'A' + 10) << bit);
489 } else if((*data >= 'a') && (*data <= 'f')) {
490 this |= (this & 0x0F) | ((*data - 'a' + 10) << bit);
d3372da9 491 } else if((*data >= '0') && (*data <= '9')) {
b9707562 492 this |= (this & 0x0F) | ((*data - '0') << bit);
493 } else if(*data == '\n') {
494 continue;
d3372da9 495 } else {
496 if(buf != NULL)
497 free(buf);
498 return(NULL);
499 }
b9707562 500 if(bit == 4) {
501 bit = 0;
d3372da9 502 } else {
b9707562 503 bit = 4;
504 addtobuf(buf, this);
505 this = 0;
d3372da9 506 }
b9707562 507 }
508 if(bit != 4) {
509 if(buf != NULL)
510 free(buf);
511 return(NULL);
d3372da9 512 }
513 addtobuf(buf, 0);
514 if(len != NULL)
515 *len = bufdata - 1;
516 return(buf);
517}
518
519char *base64encode(char *data, size_t datalen)
520{
521 char *buf;
522 size_t bufsize, bufdata;
523
524 if(datalen == 0)
525 return(sstrdup(""));
526 buf = NULL;
527 bufsize = bufdata = 0;
528 while(datalen >= 3)
529 {
530 addtobuf(buf, base64set[(data[0] & 0xfc) >> 2]);
531 addtobuf(buf, base64set[((data[0] & 0x03) << 4) | ((data[1] & 0xf0) >> 4)]);
532 addtobuf(buf, base64set[((data[1] & 0x0f) << 2) | ((data[2] & 0xc0) >> 6)]);
533 addtobuf(buf, base64set[data[2] & 0x3f]);
534 datalen -= 3;
535 data += 3;
536 }
537 if(datalen == 1)
538 {
539 addtobuf(buf, base64set[(data[0] & 0xfc) >> 2]);
540 addtobuf(buf, base64set[(data[0] & 0x03) << 4]);
541 bufcat(buf, "==", 2);
542 }
543 if(datalen == 2)
544 {
545 addtobuf(buf, base64set[(data[0] & 0xfc) >> 2]);
546 addtobuf(buf, base64set[((data[0] & 0x03) << 4) | ((data[1] & 0xf0) >> 4)]);
547 addtobuf(buf, base64set[(data[1] & 0x0f) << 2]);
548 addtobuf(buf, '=');
549 }
550 addtobuf(buf, 0);
551 return(buf);
552}
553
554char *base64decode(char *data, size_t *datalen)
555{
556 int b, c;
557 char *buf, cur;
558 size_t bufsize, bufdata;
559
560 buf = NULL;
561 bufsize = bufdata = 0;
562 cur = 0;
563 b = 8;
564 for(; *data > 0; data++)
565 {
566 c = (int)(unsigned char)*data;
567 if(c == '=')
568 break;
65399bc2 569 if(c == '\n')
570 continue;
d3372da9 571 if(base64rev[c] == -1)
572 {
573 if(buf != NULL)
574 free(buf);
575 return(NULL);
576 }
577 b -= 6;
578 if(b <= 0)
579 {
580 cur |= base64rev[c] >> -b;
581 addtobuf(buf, cur);
582 b += 8;
583 cur = 0;
584 }
585 cur |= base64rev[c] << b;
586 }
587 if(datalen != NULL)
588 *datalen = bufdata;
589 addtobuf(buf, 0);
590 return(buf);
591}
592
593char *base32encode(char *data, size_t datalen)
594{
595 char *buf;
596 size_t bufsize, bufdata;
597
598 if(datalen == 0)
599 return(sstrdup(""));
600 buf = NULL;
601 bufsize = bufdata = 0;
602 while(datalen >= 5)
603 {
604 addtobuf(buf, base32set[((data[0] & 0xf8) >> 3)]);
605 addtobuf(buf, base32set[((data[0] & 0x07) << 2) | ((data[1] & 0xc0) >> 6)]);
606 addtobuf(buf, base32set[((data[1] & 0x3e) >> 1)]);
607 addtobuf(buf, base32set[((data[1] & 0x01) << 4) | ((data[2] & 0xf0) >> 4)]);
608 addtobuf(buf, base32set[((data[2] & 0x0f) << 1) | ((data[3] & 0x80) >> 7)]);
609 addtobuf(buf, base32set[((data[3] & 0x7c) >> 2)]);
610 addtobuf(buf, base32set[((data[3] & 0x03) << 3) | ((data[4] & 0xe0) >> 5)]);
611 addtobuf(buf, base32set[data[4] & 0x1f]);
612 datalen -= 5;
613 data += 5;
614 }
615 if(datalen == 1)
616 {
617 addtobuf(buf, base32set[((data[0] & 0xf8) >> 3)]);
618 addtobuf(buf, base32set[((data[0] & 0x07) << 2)]);
619 bufcat(buf, "======", 6);
620 }
621 if(datalen == 2)
622 {
623 addtobuf(buf, base32set[((data[0] & 0xf8) >> 3)]);
624 addtobuf(buf, base32set[((data[0] & 0x07) << 2) | ((data[1] & 0xc0) >> 6)]);
625 addtobuf(buf, base32set[((data[1] & 0x3e) >> 1)]);
626 addtobuf(buf, base32set[((data[1] & 0x01) << 4)]);
627 bufcat(buf, "====", 4);
628 }
629 if(datalen == 3)
630 {
631 addtobuf(buf, base32set[((data[0] & 0xf8) >> 3)]);
632 addtobuf(buf, base32set[((data[0] & 0x07) << 2) | ((data[1] & 0xc0) >> 6)]);
633 addtobuf(buf, base32set[((data[1] & 0x3e) >> 1)]);
634 addtobuf(buf, base32set[((data[1] & 0x01) << 4) | ((data[2] & 0xf0) >> 4)]);
635 addtobuf(buf, base32set[((data[2] & 0x0f) << 1)]);
636 bufcat(buf, "===", 3);
637 }
638 if(datalen == 4)
639 {
640 addtobuf(buf, base32set[((data[0] & 0xf8) >> 3)]);
641 addtobuf(buf, base32set[((data[0] & 0x07) << 2) | ((data[1] & 0xc0) >> 6)]);
642 addtobuf(buf, base32set[((data[1] & 0x3e) >> 1)]);
643 addtobuf(buf, base32set[((data[1] & 0x01) << 4) | ((data[2] & 0xf0) >> 4)]);
644 addtobuf(buf, base32set[((data[2] & 0x0f) << 1) | ((data[3] & 0x80) >> 7)]);
645 addtobuf(buf, base32set[((data[3] & 0x7c) >> 2)]);
646 addtobuf(buf, base32set[((data[3] & 0x03) << 3)]);
647 bufcat(buf, "=", 1);
648 }
649 addtobuf(buf, 0);
650 return(buf);
651}
652
653char *base32decode(char *data, size_t *datalen)
654{
655 int b, c;
656 char *buf, cur;
657 size_t bufsize, bufdata;
658
659 buf = NULL;
660 bufsize = bufdata = 0;
661 cur = 0;
662 b = 8;
663 for(; *data > 0; data++)
664 {
665 c = (int)(unsigned char)*data;
666 if(c == '=')
667 break;
65399bc2 668 if(c == '\n')
669 continue;
d3372da9 670 if(base32rev[c] == -1)
671 {
672 if(buf != NULL)
673 free(buf);
674 return(NULL);
675 }
676 b -= 5;
677 if(b <= 0)
678 {
679 cur |= base32rev[c] >> -b;
680 addtobuf(buf, cur);
681 b += 8;
682 cur = 0;
683 }
684 cur |= base32rev[c] << b;
685 }
686 if(datalen != NULL)
687 *datalen = bufdata;
688 addtobuf(buf, 0);
689 return(buf);
690}
691
692void _freeparr(void **arr)
693{
694 void **buf;
695
696 if(arr == NULL)
697 return;
698 for(buf = arr; *buf != NULL; buf++)
699 free(*buf);
700 free(arr);
701}
702
703int _parrlen(void **arr)
704{
705 int i;
706
707 if(arr == NULL)
708 return(0);
709 for(i = 0; *arr != NULL; arr++)
710 i++;
711 return(i);
712}
713
714char *getetcpath(char *binpath)
715{
73247114 716 int f;
d3372da9 717 char *etcpath, *p;
718 size_t etcpathsize, etcpathdata;
719
720 etcpath = NULL;
721 etcpathsize = etcpathdata = 0;
73247114 722 f = 1;
d3372da9 723 do
724 {
73247114 725 if(f)
726 f = 0;
727 else
728 binpath++;
d3372da9 729 for(p = binpath; *p && (*p != ':'); p++);
730 for(; (p >= binpath) && (*p != '/'); p--);
731 if(p >= binpath)
732 {
733 if(etcpathdata > 0)
734 addtobuf(etcpath, ':');
735 bufcat(etcpath, binpath, p - binpath + 1);
736 bufcat(etcpath, "etc", 3);
737 }
738 } while((binpath = strchr(binpath, ':')) != NULL);
739 addtobuf(etcpath, 0);
740 return(etcpath);
741}
742
1df8650c 743char *findfile(char *name, char *homedir, int filldef)
d3372da9 744{
745 char *path, *binpath, *etcpath, *p;
48b2d6d1 746 struct passwd *pw;
1df8650c 747 int mode, homeonly;
d3372da9 748
1df8650c 749 if(name == NULL)
750 return(NULL);
751
41ac4371 752 mode = R_OK | (filldef ? W_OK : 0);
1df8650c 753 homeonly = homedir != NULL;
754
755 if(!strchr(name, '/'))
756 {
41ac4371 757 if(homedir == NULL)
758 homedir = getenv("HOME");
48b2d6d1 759 if((homedir == NULL) && ((pw = getpwuid(getuid())) != NULL))
760 homedir = pw->pw_dir;
1df8650c 761 if((homedir != NULL) && ((path = sprintf2("%s/.%s", homedir, name)) != NULL))
48b2d6d1 762 {
41ac4371 763 if(!access(path, mode))
48b2d6d1 764 return(path);
765 free(path);
766 }
d3372da9 767 }
1df8650c 768
769 if(!homeonly)
d3372da9 770 {
1df8650c 771 if(strchr(name, '/') != NULL)
d3372da9 772 {
1df8650c 773 if(!access(name, mode))
774 return(sstrdup(name));
d3372da9 775 } else {
776 if((binpath = getenv("PATH")) == NULL)
777 etcpath = sstrdup("/usr/local/etc:/etc:/usr/etc");
778 else
779 etcpath = getetcpath(binpath);
780 for(p = strtok(etcpath, ":"); p != NULL; p = strtok(NULL, ":"))
781 {
1df8650c 782 if((path = sprintf2("%s/%s", p, name)) != NULL)
d3372da9 783 {
41ac4371 784 if(!access(path, mode))
d3372da9 785 {
786 free(etcpath);
787 return(path);
788 }
789 free(path);
790 }
791 }
792 free(etcpath);
793 }
794 }
1df8650c 795
48b2d6d1 796 if(filldef) {
1df8650c 797 if(homedir)
798 return(sprintf2("%s/.%s", homedir, name));
799 return(sprintf2("/etc/%s", name));
48b2d6d1 800 } else {
801 return(NULL);
802 }
d3372da9 803}
9ec790e8 804
ba087e49
FT
805struct strpair *newstrpair(char *key, char *val, struct strpair **list)
806{
807 struct strpair *pair;
808
809 pair = smalloc(sizeof(*pair));
810 memset(pair, 0, sizeof(*pair));
811 if(key != NULL)
812 pair->key = sstrdup(key);
813 if(val != NULL)
814 pair->val = sstrdup(val);
815 if(list != NULL)
816 {
817 pair->next = *list;
818 *list = pair;
819 }
820 return(pair);
821}
822
823void freestrpair(struct strpair *pair, struct strpair **list)
824{
825 struct strpair *cur;
826
827 for(cur = *list; cur != NULL; list = &(cur->next), cur = cur->next)
828 {
829 if(cur == pair)
830 {
831 *list = cur->next;
832 break;
833 }
834 }
835 free(pair->key);
836 free(pair->val);
837 free(pair);
838}
839
840char *spfind(struct strpair *list, char *key)
841{
842 for(; list != NULL; list = list->next)
843 {
844 if(!strcmp(list->key, key))
845 return(list->val);
846 }
847 return(NULL);
848}
849
9ec790e8 850struct wcspair *newwcspair(wchar_t *key, wchar_t *val, struct wcspair **list)
851{
852 struct wcspair *pair;
853
854 pair = smalloc(sizeof(*pair));
855 memset(pair, 0, sizeof(*pair));
856 if(key != NULL)
857 pair->key = swcsdup(key);
858 if(val != NULL)
859 pair->val = swcsdup(val);
ba087e49 860 if(list != NULL)
9ec790e8 861 {
9ec790e8 862 pair->next = *list;
863 *list = pair;
864 }
865 return(pair);
866}
867
868void freewcspair(struct wcspair *pair, struct wcspair **list)
869{
497fe07b 870 struct wcspair *cur;
871
872 for(cur = *list; cur != NULL; list = &(cur->next), cur = cur->next)
9ec790e8 873 {
497fe07b 874 if(cur == pair)
875 {
876 *list = cur->next;
877 break;
878 }
9ec790e8 879 }
880 free(pair->key);
881 free(pair->val);
882 free(pair);
883}
a2761258 884
885wchar_t *wpfind(struct wcspair *list, wchar_t *key)
886{
887 for(; list != NULL; list = list->next)
888 {
889 if(!wcscmp(list->key, key))
890 return(list->val);
891 }
892 return(NULL);
893}