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