ind.c - rohrpost - A commandline mail client to change the world as we see it.
(HTM) git clone git://r-36.net/rohrpost
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
ind.c (8246B)
---
1 /*
2 * Copy me if you can.
3 * by 20h
4 */
5
6 #include <unistd.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stdarg.h>
10 #include <fcntl.h>
11 #include <string.h>
12 #include <strings.h>
13 #include <errno.h>
14 #include <ctype.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <time.h>
18 #include <limits.h>
19
20 #include "ind.h"
21
22 void
23 edie(char *fmt, ...)
24 {
25 va_list fmtargs;
26
27 va_start(fmtargs, fmt);
28 vfprintf(stderr, fmt, fmtargs);
29 va_end(fmtargs);
30 fprintf(stderr, ": ");
31
32 perror(NULL);
33
34 exit(1);
35 }
36
37 void
38 die(char *fmt, ...)
39 {
40 va_list fmtargs;
41
42 va_start(fmtargs, fmt);
43 vfprintf(stderr, fmt, fmtargs);
44 va_end(fmtargs);
45
46 exit(1);
47 }
48
49 void *
50 reallocz(void *p, int l, int z)
51 {
52 p = realloc(p, l);
53 if(p == NULL)
54 edie("realloc");
55 if(z)
56 memset(p, 0, l);
57
58 return p;
59 }
60
61 void *
62 mallocz(int l, int z)
63 {
64 return reallocz(NULL, l, z);
65 }
66
67 void *
68 memdup(void *p, int l)
69 {
70 char *ret;
71
72 ret = reallocz(NULL, l, 2);
73 memmove(ret, p, l);
74
75 return (void *)ret;
76 }
77
78 void *
79 memdupz(void *p, int l)
80 {
81 char *ret;
82
83 ret = reallocz(NULL, l+1, 2);
84 memmove(ret, p, l);
85
86 return (void *)ret;
87 }
88
89 void *
90 memdups(void *p)
91 {
92 char *ret;
93 int l;
94
95 l = strlen(p) + 1;
96
97 ret = reallocz(NULL, l, 2);
98 memmove(ret, p, l);
99
100 return (void *)ret;
101 }
102
103 /*
104 * Append the data at c with the length of lc to
105 * p, at position lp of p.
106 */
107 void *
108 memdupcat(void *p, int lp, void *c, int lc)
109 {
110 p = reallocz(p, lp+lc, 0);
111 memset(&((char *)p)[lp], 0, lc);
112
113 memmove(&((char *)p)[lp], c, lc);
114
115 return p;
116 }
117
118 char *
119 vsmprintf(char *fmt, va_list fmtargs, int size)
120 {
121 char *ret;
122
123 ret = reallocz(NULL, ++size, 2);
124 vsnprintf(ret, size, fmt, fmtargs);
125
126 return ret;
127 }
128
129 char *
130 smprintf(char *fmt, ...)
131 {
132 va_list fmtargs;
133 char *ret;
134 int len;
135
136 va_start(fmtargs, fmt);
137 len = vsnprintf(NULL, 0, fmt, fmtargs);
138 va_end(fmtargs);
139
140 if (len == INT_MAX)
141 return NULL;
142
143 va_start(fmtargs, fmt);
144 ret = vsmprintf(fmt, fmtargs, len);
145 va_end(fmtargs);
146
147 return ret;
148 }
149
150 void
151 setnonblocking(int fd)
152 {
153 int opts;
154
155 opts = fcntl(fd, F_GETFL);
156 if(opts < 0)
157 edie("setnonblocking");
158
159 if(fcntl(fd, F_SETFL, opts | O_NONBLOCK) < 0)
160 edie("setnonblocking");
161 }
162
163 void
164 setblocking(int fd)
165 {
166 int opts;
167
168 opts = fcntl(fd, F_GETFL);
169 if(opts < 0)
170 edie("setblocking");
171
172 if(fcntl(fd, F_SETFL, opts & ~O_NONBLOCK) < 0)
173 edie("setblocking");
174 }
175
176 int
177 runcmd(char *cmd, int *infd, int *outfd, int *errfd, int keepold)
178 {
179 int pid, nullfd, status;
180 int pstdin[2], pstdout[2], pstderr[2];
181
182 enum {
183 DOSTDOUT = 0x01,
184 DOSTDIN = 0x02,
185 DOSTDERR = 0x04,
186 HAVENULLFD = 0x08
187 };
188
189 status = 0;
190
191 if (infd) {
192 if (pipe(pstdin))
193 goto runcmderror;
194 status |= DOSTDOUT;
195 }
196 if (outfd) {
197 if (pipe(pstdout))
198 goto runcmderror;
199 status |= DOSTDIN;
200 }
201 if (errfd) {
202 if (pipe(pstderr))
203 goto runcmderror;
204 status |= DOSTDERR;
205 }
206 if (!keepold && ((status & DOSTDIN) || (status & DOSTDOUT)
207 || (status & DOSTDERR))) {
208 nullfd = open("/dev/null", O_RDWR);
209 if (nullfd < 0)
210 goto runcmderror;
211 status |= HAVENULLFD;
212 }
213
214 pid = fork();
215 switch(pid) {
216 case -1:
217 return pid;
218 case 0:
219 if (status & DOSTDIN) {
220 close(pstdin[1]);
221 dup2(pstdin[0], 0);
222 } else {
223 if (!keepold)
224 dup2(nullfd, 0);
225 }
226 if (status & DOSTDOUT) {
227 close(pstdout[0]);
228 dup2(pstdout[1], 1);
229 } else {
230 if (!keepold)
231 dup2(nullfd, 1);
232 }
233 if (status & DOSTDERR) {
234 close(pstderr[1]);
235 dup2(pstderr[0], 2);
236 } else {
237 if (!keepold)
238 dup2(nullfd, 2);
239 }
240
241 execl("/bin/sh", "sh", "-c", cmd, NULL);
242 exit(1);
243 default:
244 break;
245 }
246
247 if (status & DOSTDIN) {
248 close(pstdin[0]);
249 *infd = pstdin[1];
250 }
251 if (status & DOSTDOUT) {
252 close(pstdout[1]);
253 *outfd = pstdout[0];
254 }
255 if (status & DOSTDERR) {
256 close(pstderr[1]);
257 *errfd = pstderr[1];
258 }
259
260 return pid;
261 runcmderror:
262 if (status & DOSTDIN) {
263 close(pstdin[0]);
264 close(pstdin[1]);
265 }
266 if (status & DOSTDOUT) {
267 close(pstdout[0]);
268 close(pstdout[1]);
269 }
270 if (status & DOSTDERR) {
271 close(pstderr[0]);
272 close(pstderr[1]);
273 }
274 if (status & HAVENULLFD)
275 close(nullfd);
276
277 return -1;
278 }
279
280 char *
281 expandhome(char *path)
282 {
283 char *home, *retpath;
284
285 retpath = NULL;
286
287 if (path[0] == '~') {
288 home = getenv("HOME");
289 if (home != NULL)
290 retpath = smprintf("%s%s", home, path+1);
291 }
292 if (retpath == NULL)
293 retpath = memdups(path);
294
295 return retpath;
296 }
297
298 int
299 writeall(FILE *fd, void *data, int len)
300 {
301 int written;
302
303 for (written = 0; len > 0; ) {
304 written = fwrite(data, 1, len, fd);
305 len -= written;
306 }
307
308 return 0;
309 }
310
311 int
312 writeallfd(int fd, void *data, int len)
313 {
314 int written;
315
316 for (written = 0; len > 0; ) {
317 written = write(fd, &((char *)data)[written], len);
318 len -= written;
319 }
320
321 return 0;
322 }
323
324 int
325 writefile(char *file, void *data, int len, char *mode)
326 {
327 FILE *fd;
328
329 fd = fopen(file, mode);
330 if (fd == NULL)
331 return 1;
332 if (writeall(fd, data, len))
333 return 1;
334 fclose(fd);
335
336 return 0;
337 }
338
339 int
340 getfilesize(char *file)
341 {
342 struct stat fs;
343
344 if (stat(file, &fs) < 0)
345 return -1;
346
347 return fs.st_size;
348 }
349
350 char *
351 readtoeof(FILE *fd, int *len)
352 {
353 char *ret, buf[4096];
354 int olen, nlen, rl;
355
356 for (nlen = 0, olen = 0, ret = NULL; !feof(fd); olen = nlen) {
357 rl = fread(buf, 1, sizeof(buf), fd);
358 if (rl > 0) {
359 nlen += rl;
360 ret = reallocz(ret, nlen+1, 0);
361 ret[nlen] = '\0';
362
363 memmove(&ret[olen], buf, rl);
364 }
365 }
366
367 *len = nlen;
368 return ret;
369 }
370
371 char *
372 readtoeoffd(int fd, int *len)
373 {
374 char *ret, buf[4096];
375 int olen, nlen, rl;
376
377 for (nlen = 0, olen = 0, ret = NULL;
378 (rl = read(fd, buf, sizeof(buf))); olen = nlen) {
379 if (rl > 0) {
380 nlen += rl;
381 ret = reallocz(ret, nlen+1, 0);
382 ret[nlen] = '\0';
383
384 memmove(&ret[olen], buf, rl);
385 }
386 }
387
388 *len = nlen;
389 return ret;
390 }
391
392 char *
393 readfile(char *file, int *len)
394 {
395 FILE *fd;
396 char *data;
397
398 fd = fopen(file, "r");
399 if (fd == NULL)
400 return NULL;
401
402 data = readtoeof(fd, len);
403 fclose(fd);
404
405 return data;
406 }
407
408 char *
409 readstdin(int *len)
410 {
411 return readtoeof(stdin, len);
412 }
413
414 /*
415 * Get line from string buffer.
416 */
417 char *
418 sgets(char *s, int size, char **p)
419 {
420 char *np;
421 int cl;
422
423 if (*p == NULL)
424 return NULL;
425
426 np = strchr(*p, '\n');
427 if (np == NULL) {
428 cl = strlen(*p);
429 if (cl < 1) {
430 *p = NULL;
431 return NULL;
432 }
433 } else {
434 cl = np - *p;
435 }
436
437 if (cl >= size)
438 cl = size - 1;
439 memmove(s, *p, cl);
440 s[cl] = '\0';
441
442 if (np == NULL) {
443 *p = NULL;
444 } else {
445 *p = np+1;
446 }
447
448 return s;
449 }
450
451 char *
452 sgetuntil(char *str, char **p, char *max, int *len)
453 {
454 char *ret, *op;
455 int si;
456
457 ret = NULL;
458
459 si = 0;
460 for (op = *p; op < max; op++) {
461 if (str[si] == '\0')
462 break;
463 if (op[0] == str[si]) {
464 si++;
465 } else {
466 si = 0;
467 }
468 }
469 if (str[si] == '\0') {
470 *len = op - *p - strlen(str);
471 ret = memdupz(*p, *len);
472 *p = op;
473 }
474
475 return ret;
476 }
477
478 char *
479 strrlnspn(char *p, char *chars, int limit)
480 {
481 char *np;
482
483 np = &p[limit-1];
484 for(; !strchr(chars, np[0] && p != np); np--);
485
486 return np;
487 }
488
489 int
490 strisascii(char *str)
491 {
492 int len, i;
493
494 len = strlen(str);
495 for (i = 0; i < len; i++) {
496 if (!isascii(str[i]))
497 return 0;
498 }
499
500 return 1;
501 }
502
503 void
504 strnormalizespace(char *str)
505 {
506 int len, i;
507
508 len = strlen(str);
509 for (i = 0; i < len; i++) {
510 if (isspace(str[i]))
511 str[i] = ' ';
512 }
513 }
514
515 /*
516 * Find a whitespace character in a certain limit. This is used for formatting
517 * mail to a certain width.
518 */
519 char *
520 findlimitws(char *str, int limit)
521 {
522 int len;
523 char *ptr;
524
525 len = strlen(str);
526 if (len < limit)
527 return NULL;
528
529 ptr = strrlnspn(str, "\t\r\v\f ", limit);
530 if (ptr == str)
531 return &str[limit-1];
532 return ptr;
533 }
534
535 char *
536 mktmpfile(char *prefix, char *suffix, int *fd)
537 {
538 char *name;
539 time_t tm;
540 int tfd;
541
542 tm = time(NULL);
543 srand(tm);
544
545 for (tfd = -1; tfd < 0;) {
546 name = smprintf("/tmp/%s.%d.%d.%s", prefix, getpid(), rand(),
547 suffix);
548 tfd = open(name, O_EXCL|O_CREAT|O_RDWR|O_TRUNC,
549 S_IRUSR|S_IWUSR);
550 if (tfd >= 0)
551 break;
552 if (tfd < 0 && errno != EEXIST)
553 edie("mktmpfile");
554 free(name);
555 }
556
557 *fd = tfd;
558
559 return name;
560 }
561
562 int
563 intcmp(const void *p1, const void *p2)
564 {
565 return *((int *)p1) - *((int *)p2);
566 }
567
568 char *
569 smftime(char *fmt, const struct tm *tm)
570 {
571 int len, rlen;
572 char *ret;
573
574 len = strlen(fmt);
575 ret = NULL;
576 for (; len < 1024;) {
577 len *= 2;
578 ret = reallocz(ret, len, 0);
579 rlen = strftime(ret, len, fmt, tm);
580 if (rlen == 0)
581 continue;
582 }
583
584 return ret;
585 }
586