Mercurial > hg > Applications > mh
comparison uip/popi.c @ 0:bce86c4163a3
Initial revision
author | kono |
---|---|
date | Mon, 18 Apr 2005 23:46:02 +0900 |
parents | |
children | a6481689f99c |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:bce86c4163a3 |
---|---|
1 /* popi.c - POP initiator - for MPOP */ | |
2 #ifndef lint | |
3 static char ident[] = "@(#)$Id$"; | |
4 #endif lint | |
5 | |
6 #include "../h/mh.h" | |
7 #include "../h/formatsbr.h" | |
8 #include "../h/scansbr.h" | |
9 #include <errno.h> | |
10 #include <stdio.h> | |
11 #include <sys/types.h> | |
12 #ifdef SMTP | |
13 #include "../h/local.h" | |
14 #else /* SMTP */ | |
15 #include <sys/stat.h> | |
16 #endif /* SMTP */ | |
17 #include "../zotnet/mts.h" | |
18 #ifdef SYS5DIR | |
19 #include <stdlib.h> | |
20 #endif | |
21 | |
22 /* */ | |
23 | |
24 #ifndef RPOP | |
25 #define RPOPminc(a) (a) | |
26 #else | |
27 #define RPOPminc(a) 0 | |
28 #endif | |
29 | |
30 #ifndef APOP | |
31 #define APOPminc(a) (a) | |
32 #else | |
33 #define APOPminc(a) 0 | |
34 #endif | |
35 | |
36 #if !defined(BPOP) || defined(NNTP) | |
37 #define BPOPminc(a) (a) | |
38 #else | |
39 #define BPOPminc(a) 0 | |
40 #endif | |
41 | |
42 #ifndef SMTP | |
43 #define BULKminc(a) (a) | |
44 #else | |
45 #define BULKminc(a) 0 | |
46 #endif | |
47 | |
48 static struct swit switches[] = { | |
49 #define APOPSW 0 | |
50 "apop", APOPminc (-4), | |
51 #define NAPOPSW 1 | |
52 "noapop", APOPminc (-6), | |
53 | |
54 #define AUTOSW 2 | |
55 "auto", BPOPminc(-4), | |
56 #define NAUTOSW 3 | |
57 "noauto", BPOPminc(-6), | |
58 | |
59 #define BULKSW 4 | |
60 "bulk directory", BULKminc(-4), | |
61 | |
62 #define FORMSW 5 | |
63 "form formatfile", 0, | |
64 | |
65 #define FMTSW 6 | |
66 "format string", 5, | |
67 | |
68 #define HOSTSW 7 | |
69 "host host", 0, | |
70 | |
71 #define PROGSW 8 | |
72 "mshproc program", 0, | |
73 | |
74 #define RPOPSW 9 | |
75 "rpop", RPOPminc (-4), | |
76 #define NRPOPSW 10 | |
77 "norpop", RPOPminc (-6), | |
78 | |
79 #define USERSW 11 | |
80 "user user", 0, | |
81 | |
82 #define WIDSW 12 | |
83 "width columns", 0, | |
84 | |
85 #define HELPSW 13 | |
86 "help", 4, | |
87 | |
88 NULL, 0 | |
89 }; | |
90 | |
91 /* */ | |
92 | |
93 static char *bulksw = NULLCP; | |
94 static int snoop = 0; | |
95 static int width = 0; | |
96 | |
97 static char mailname[BUFSIZ]; | |
98 | |
99 static char *nfs = NULL; | |
100 | |
101 static struct msgs *mp; | |
102 | |
103 extern int errno; | |
104 | |
105 extern char response[]; | |
106 | |
107 static popi(), retr_action(); | |
108 #if defined(BPOP) && !defined(NNTP) | |
109 static msh(); | |
110 #endif | |
111 #ifdef SMTP | |
112 static do_bulk(); | |
113 #endif | |
114 | |
115 /* */ | |
116 | |
117 /* ARGSUSED */ | |
118 | |
119 main (argc, argv) | |
120 int argc; | |
121 char *argv[]; | |
122 { | |
123 int autosw = 1, | |
124 noisy = 1, | |
125 rpop; | |
126 char *cp, | |
127 *maildir, | |
128 *folder = NULL, | |
129 *form = NULL, | |
130 *format = NULL, | |
131 *host = NULL, | |
132 *user = NULL, | |
133 *pass = NULL, | |
134 buf[100], | |
135 **ap, | |
136 **argp, | |
137 *arguments[MAXARGS]; | |
138 struct stat st; | |
139 | |
140 invo_name = r1bindex (argv[0], '/'); | |
141 mts_init (invo_name); | |
142 if (pophost && *pophost) | |
143 host = pophost; | |
144 if ((cp = getenv ("MHPOPDEBUG")) && *cp) | |
145 snoop++; | |
146 if ((cp = m_find (invo_name)) != NULL) { | |
147 ap = brkstring (cp = getcpy (cp), " ", "\n"); | |
148 ap = copyip (ap, arguments); | |
149 } | |
150 else | |
151 ap = arguments; | |
152 (void) copyip (argv + 1, ap); | |
153 argp = arguments; | |
154 | |
155 rpop = getuid () && !geteuid (); | |
156 | |
157 /* */ | |
158 | |
159 while (cp = *argp++) { | |
160 if (*cp == '-') | |
161 switch (smatch (++cp, switches)) { | |
162 case AMBIGSW: | |
163 ambigsw (cp, switches); | |
164 done (1); | |
165 case UNKWNSW: | |
166 adios (NULLCP, "-%s unknown", cp); | |
167 case HELPSW: | |
168 (void) sprintf (buf, "%s [+folder] [switches]", invo_name); | |
169 help (buf, switches); | |
170 done (1); | |
171 | |
172 case AUTOSW: | |
173 autosw = 1; | |
174 continue; | |
175 case NAUTOSW: | |
176 autosw = 0; | |
177 continue; | |
178 | |
179 case BULKSW: | |
180 if (!(bulksw = *argp++) || *bulksw == '-') | |
181 adios (NULLCP, "missing argument to %s", argp[-2]); | |
182 continue; | |
183 | |
184 case FORMSW: | |
185 if (!(form = *argp++) || *form == '-') | |
186 adios (NULLCP, "missing argument to %s", argp[-2]); | |
187 format = NULL; | |
188 continue; | |
189 case FMTSW: | |
190 if (!(format = *argp++) || *format == '-') | |
191 adios (NULLCP, "missing argument to %s", argp[-2]); | |
192 form = NULL; | |
193 continue; | |
194 | |
195 case WIDSW: | |
196 if (!(cp = *argp++) || *cp == '-') | |
197 adios (NULLCP, "missing argument to %s", argp[-2]); | |
198 width = atoi (cp); | |
199 continue; | |
200 | |
201 case HOSTSW: | |
202 if (!(host = *argp++) || *host == '-') | |
203 adios (NULLCP, "missing argument to %s", argp[-2]); | |
204 continue; | |
205 case USERSW: | |
206 if (!(user = *argp++) || *user == '-') | |
207 adios (NULLCP, "missing argument to %s", argp[-2]); | |
208 continue; | |
209 | |
210 case APOPSW: | |
211 rpop = -1; | |
212 continue; | |
213 case RPOPSW: | |
214 rpop = 1; | |
215 continue; | |
216 case NAPOPSW: | |
217 case NRPOPSW: | |
218 rpop = 0; | |
219 continue; | |
220 | |
221 case PROGSW: | |
222 if (!(mshproc = *argp++) || *mshproc == '-') | |
223 adios (NULLCP, "missing argument to %s", argp[-2]); | |
224 continue; | |
225 } | |
226 if (*cp == '+' || *cp == '@') { | |
227 if (folder) | |
228 adios (NULLCP, "only one folder at a time!"); | |
229 else | |
230 folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF); | |
231 } | |
232 else | |
233 adios (NULLCP, "usage: %s [+folder] [switches]", invo_name); | |
234 } | |
235 | |
236 /* */ | |
237 | |
238 if (!host) | |
239 adios (NULLCP, "usage: %s -host \"host\"", invo_name); | |
240 | |
241 #ifdef SMTP | |
242 if (bulksw) | |
243 do_bulk (host); | |
244 #endif | |
245 | |
246 if (user == NULL) | |
247 user = getusr (); | |
248 if (rpop > 0) | |
249 pass = getusr (); | |
250 else { | |
251 (void) setuid (getuid ()); | |
252 ruserpass (host, &user, &pass); | |
253 } | |
254 (void) sprintf (mailname, "PO box for %s@%s", user, host); | |
255 | |
256 if (pop_init (host, user, pass, snoop, rpop) == NOTOK) | |
257 adios (NULLCP, "%s", response); | |
258 if (rpop > 0) | |
259 (void) setuid (getuid ()); | |
260 | |
261 nfs = new_fs (form, format, FORMAT); | |
262 | |
263 if (!m_find ("path")) | |
264 free (path ("./", TFOLDER)); | |
265 if (!folder && !(folder = m_find (inbox))) | |
266 folder = defalt; | |
267 maildir = m_maildir (folder); | |
268 | |
269 if (stat (maildir, &st) == NOTOK) { | |
270 if (errno != ENOENT) | |
271 adios (maildir, "error on folder"); | |
272 cp = concat ("Create folder \"", maildir, "\"? ", NULLCP); | |
273 if (noisy && !getanswer (cp)) | |
274 done (1); | |
275 free (cp); | |
276 if (!makedir (maildir)) | |
277 adios (NULLCP, "unable to create folder %s", maildir); | |
278 } | |
279 | |
280 if (chdir (maildir) == NOTOK) | |
281 adios (maildir, "unable to change directory to"); | |
282 if (!(mp = m_gmsg (folder))) | |
283 adios (NULLCP, "unable to read folder %s", folder); | |
284 | |
285 #if defined(BPOP) && !defined(NNTP) | |
286 if (autosw) | |
287 msh (); | |
288 else | |
289 #endif | |
290 popi (); | |
291 | |
292 (void) pop_quit (); | |
293 | |
294 m_replace (pfolder, folder); | |
295 m_setvis (mp, 0); | |
296 m_sync (mp); | |
297 m_update (); | |
298 | |
299 done (0); | |
300 | |
301 /* NOTREACHED */ | |
302 } | |
303 | |
304 /* */ | |
305 | |
306 static struct swit popicmds[] = { | |
307 #define DELECMD 0 | |
308 "dele", 0, | |
309 #define LASTCMD 1 | |
310 "last", 0, | |
311 #define LISTCMD 2 | |
312 "list", 0, | |
313 #define NOOPCMD 3 | |
314 "noop", 0, | |
315 #define QUITCMD 4 | |
316 "quit", 0, | |
317 #define RETRCMD 5 | |
318 "retr", 0, | |
319 #define RSETCMD 6 | |
320 "rset", 0, | |
321 #define SCANCMD 7 | |
322 "scan", 0, | |
323 #define STATCMD 8 | |
324 "stat", 0, | |
325 #define TOPCMD 9 | |
326 "top", 0, | |
327 #if defined(BPOP) && !defined(NNTP) | |
328 #define MSHCMD 10 | |
329 "msh", 0, | |
330 #endif | |
331 | |
332 NULL, 0 | |
333 }; | |
334 | |
335 /* */ | |
336 | |
337 static popi () | |
338 { | |
339 int eof; | |
340 | |
341 eof = 0; | |
342 for (;;) { | |
343 int i; | |
344 register char *cp; | |
345 char buffer[BUFSIZ]; | |
346 | |
347 if (eof) | |
348 return; | |
349 | |
350 printf ("(%s) ", invo_name); | |
351 for (cp = buffer; (i = getchar ()) != '\n'; ) { | |
352 if (i == EOF) { | |
353 (void) putchar ('\n'); | |
354 if (cp == buffer) | |
355 return; | |
356 eof = 1; | |
357 break; | |
358 } | |
359 | |
360 if (cp < buffer + sizeof buffer - 2) | |
361 *cp++ = i; | |
362 } | |
363 *cp = '\0'; | |
364 if (buffer[0] == '\0') | |
365 continue; | |
366 if (buffer[0] == '?') { | |
367 printf ("commands:\n"); | |
368 printsw (ALL, popicmds, ""); | |
369 printf ("type CTRL-D or use \"quit\" to leave %s\n", invo_name); | |
370 continue; | |
371 } | |
372 | |
373 if (cp = index (buffer, ' ')) | |
374 *cp = '\0'; | |
375 switch (i = smatch (buffer, popicmds)) { | |
376 case AMBIGSW: | |
377 ambigsw (buffer, popicmds); | |
378 continue; | |
379 case UNKWNSW: | |
380 printf ("%s unknown -- type \"?\" for help\n", buffer); | |
381 continue; | |
382 | |
383 case QUITCMD: | |
384 return; | |
385 | |
386 case STATCMD: | |
387 case DELECMD: | |
388 case NOOPCMD: | |
389 case LASTCMD: | |
390 case RSETCMD: | |
391 case TOPCMD: | |
392 if (cp) | |
393 *cp = ' '; | |
394 (void) pop_command ("%s%s", popicmds[i].sw, cp ? cp : ""); | |
395 printf ("%s\n", response); | |
396 break; | |
397 | |
398 case LISTCMD: | |
399 if (cp) | |
400 *cp = ' '; | |
401 if (pop_command ("%s%s", popicmds[i].sw, cp ? cp : "") | |
402 == OK) { | |
403 printf ("%s\n", response); | |
404 if (!cp) | |
405 for (;;) { | |
406 switch (pop_multiline ()) { | |
407 case DONE: | |
408 (void) strcpy (response, "."); | |
409 /* and fall... */ | |
410 case NOTOK: | |
411 printf ("%s\n", response); | |
412 break; | |
413 | |
414 case OK: | |
415 printf ("%s\n", response); | |
416 continue; | |
417 } | |
418 break; | |
419 } | |
420 } | |
421 break; | |
422 | |
423 case RETRCMD: | |
424 if (!cp) { | |
425 advise (NULLCP, "missing argument to %s", buffer); | |
426 break; | |
427 } | |
428 retr_action (NULLCP, OK); | |
429 (void) pop_retr (atoi (++cp), retr_action); | |
430 retr_action (NULLCP, DONE); | |
431 printf ("%s\n", response); | |
432 break; | |
433 | |
434 case SCANCMD: | |
435 { | |
436 char *dp, | |
437 *ep, | |
438 *fp; | |
439 | |
440 if (width == 0) | |
441 width = sc_width (); | |
442 | |
443 for (dp = nfs, i = 0; *dp; dp++, i++) | |
444 if (*dp == '\\' || *dp == '"' || *dp == '\n') | |
445 i++; | |
446 i++; | |
447 if ((ep = malloc ((unsigned) i)) == NULL) | |
448 adios (NULLCP, "out of memory"); | |
449 for (dp = nfs, fp = ep; *dp; dp++) { | |
450 if (*dp == '\n') { | |
451 *fp++ = '\\', *fp++ = 'n'; | |
452 continue; | |
453 } | |
454 if (*dp == '"' || *dp == '\\') | |
455 *fp++ = '\\'; | |
456 *fp++ = *dp; | |
457 } | |
458 *fp = '\0'; | |
459 | |
460 (void) pop_command ("xtnd scan %d \"%s\"", width, ep); | |
461 printf ("%s\n", response); | |
462 | |
463 free (ep); | |
464 } | |
465 break; | |
466 | |
467 #if defined(BPOP) && !defined(NNTP) | |
468 case MSHCMD: | |
469 msh (); | |
470 break; | |
471 #endif | |
472 } | |
473 } | |
474 } | |
475 | |
476 /* */ | |
477 | |
478 static int retr_action (rsp, flag) | |
479 char *rsp; | |
480 int flag; | |
481 { | |
482 static FILE *fp; | |
483 | |
484 if (rsp == NULL) { | |
485 static int msgnum; | |
486 static char *cp; | |
487 | |
488 if (flag == OK) { | |
489 if ((mp = m_remsg (mp, 0, msgnum = mp -> hghmsg + 1)) == NULL) | |
490 adios (NULLCP, "unable to allocate folder storage"); | |
491 | |
492 cp = getcpy (m_name (mp -> hghmsg + 1)); | |
493 if ((fp = fopen (cp, "w+")) == NULL) | |
494 adios (cp, "unable to write"); | |
495 (void) chmod (cp, m_gmprot ()); | |
496 } | |
497 else { | |
498 struct stat st; | |
499 | |
500 (void) fflush (fp); | |
501 if (fstat (fileno (fp), &st) != NOTOK && st.st_size > 0) { | |
502 mp -> msgstats[msgnum] = EXISTS | UNSEEN; | |
503 mp -> msgflags |= SEQMOD; | |
504 | |
505 if (ferror (fp)) | |
506 advise (cp, "write error on"); | |
507 mp -> hghmsg = msgnum; | |
508 } | |
509 else | |
510 (void) unlink (cp); | |
511 | |
512 (void) fclose (fp), fp = NULL; | |
513 free (cp), cp = NULL; | |
514 } | |
515 | |
516 return; | |
517 } | |
518 | |
519 fprintf (fp, "%s\n", rsp); | |
520 } | |
521 | |
522 /* */ | |
523 | |
524 #if defined(BPOP) && !defined(NNTP) | |
525 static msh () | |
526 { | |
527 int child_id, | |
528 vecp; | |
529 char buf1[BUFSIZ], | |
530 buf2[BUFSIZ], | |
531 *vec[9]; | |
532 | |
533 if (pop_fd (buf1, buf2) == NOTOK) | |
534 adios (NULLCP, "%s", response); | |
535 | |
536 vecp = 0; | |
537 vec[vecp++] = r1bindex (mshproc, '/'); | |
538 | |
539 switch (child_id = fork ()) { | |
540 case NOTOK: | |
541 adios ("fork", "unable to"); | |
542 | |
543 case OK: | |
544 vec[vecp++] = "-popread"; | |
545 vec[vecp++] = buf1; | |
546 vec[vecp++] = "-popwrite"; | |
547 vec[vecp++] = buf2; | |
548 vec[vecp++] = "-idname"; | |
549 vec[vecp++] = mailname; | |
550 vec[vecp++] = mailname; | |
551 vec[vecp] = NULL; | |
552 (void) execvp (mshproc, vec); | |
553 fprintf (stderr, "unable to exec "); | |
554 perror (mshproc); | |
555 _exit (-1); | |
556 | |
557 default: | |
558 (void) pidXwait (child_id, mshproc); | |
559 break; | |
560 } | |
561 } | |
562 #endif | |
563 | |
564 /* */ | |
565 | |
566 #ifdef SMTP | |
567 #include "../zotnet/mts.h" | |
568 #include "../mts/sendmail/smail.h" | |
569 | |
570 | |
571 static int dselect (d) | |
572 #ifdef SYS5DIR | |
573 register struct dirent *d; | |
574 #else | |
575 register struct direct *d; | |
576 #endif | |
577 { | |
578 int i; | |
579 | |
580 if ((i = strlen (d -> d_name)) < sizeof "smtp" | |
581 || strncmp (d -> d_name, "smtp", sizeof "smtp" - 1)) | |
582 return 0; | |
583 return ((i -= (sizeof ".bulk" - 1)) > 0 | |
584 && !strcmp (d -> d_name + i, ".bulk")); | |
585 } | |
586 | |
587 | |
588 static int dcompar (d1, d2) | |
589 #ifdef SYS5DIR | |
590 struct dirent **d1, | |
591 **d2; | |
592 #else | |
593 struct direct **d1, | |
594 **d2; | |
595 #endif | |
596 { | |
597 struct stat s1, | |
598 s2; | |
599 | |
600 if (stat ((*d1) -> d_name, &s1) == NOTOK) | |
601 return 1; | |
602 if (stat ((*d2) -> d_name, &s2) == NOTOK) | |
603 return -1; | |
604 return ((int) (s1.st_mtime - s2.st_mtime)); | |
605 } | |
606 | |
607 | |
608 static do_bulk (host) | |
609 char *host; | |
610 { | |
611 register int i; | |
612 int n, | |
613 retval, | |
614 sm; | |
615 #ifdef SYS5DIR | |
616 struct dirent **namelist; | |
617 #else | |
618 struct direct **namelist; | |
619 #endif | |
620 | |
621 if (chdir (bulksw) == NOTOK) | |
622 adios (bulksw, "unable to change directory to"); | |
623 | |
624 if ((n = scandir (".", &namelist, dselect, dcompar)) == NOTOK) | |
625 adios (bulksw, "unable to scan directory"); | |
626 | |
627 sm = NOTOK; | |
628 for (i = 0; i < n; i++) { | |
629 #ifdef SYS5DIR | |
630 register struct dirent *d = namelist[i]; | |
631 #else | |
632 register struct direct *d = namelist[i]; | |
633 #endif | |
634 | |
635 if (sm == NOTOK) { | |
636 if (rp_isbad (retval = sm_init (NULLCP, host, 1, 1, snoop))) | |
637 adios (NULLCP, "problem initializing server: %s", | |
638 rp_string (retval)); | |
639 else | |
640 sm = OK; | |
641 } | |
642 | |
643 switch (retval = sm_bulk (d -> d_name)) { | |
644 default: | |
645 if (rp_isbad (retval)) | |
646 adios (NULLCP, "problem delivering msg %s: %s", | |
647 d -> d_name, rp_string (retval)); | |
648 /* else fall... */ | |
649 case RP_OK: | |
650 case RP_NO: | |
651 case RP_NDEL: | |
652 advise (NULLCP, "msg %s: %s", d -> d_name, rp_string (retval)); | |
653 break; | |
654 } | |
655 } | |
656 | |
657 if (sm == OK) { | |
658 register int j; | |
659 int l, | |
660 m; | |
661 #ifdef SYS5DIR | |
662 struct dirent **newlist; | |
663 #else | |
664 struct direct **newlist; | |
665 #endif | |
666 | |
667 while ((l = scandir (".", &newlist, dselect, dcompar)) > OK) { | |
668 m = 0; | |
669 | |
670 for (j = 0; j < l; j++) { | |
671 #ifdef SYS5DIR | |
672 register struct dirent *d = newlist[j]; | |
673 #else | |
674 register struct direct *d = newlist[j]; | |
675 #endif | |
676 | |
677 for (i = 0; i < n; i++) | |
678 if (strcmp (d -> d_name, namelist[i] -> d_name) == 0) | |
679 break; | |
680 if (i >= n) { | |
681 switch (retval = sm_bulk (d -> d_name)) { | |
682 default: | |
683 if (rp_isbad (retval)) | |
684 adios (NULLCP, "problem delivering msg %s: %s", | |
685 d -> d_name, rp_string (retval)); | |
686 /* else fall... */ | |
687 case RP_OK: | |
688 case RP_NO: | |
689 case RP_NDEL: | |
690 advise (NULLCP, "msg %s: %s", d -> d_name, | |
691 rp_string (retval)); | |
692 break; | |
693 } | |
694 | |
695 m = 1; | |
696 } | |
697 } | |
698 | |
699 for (i = 0; i < n; i++) | |
700 free ((char *) namelist[i]); | |
701 free ((char *) namelist); | |
702 namelist = newlist, n = l; | |
703 | |
704 if (!m) | |
705 break; | |
706 newlist = NULL; | |
707 } | |
708 } | |
709 | |
710 if (sm == OK && rp_isbad (retval = sm_end (OK))) | |
711 adios (NULLCP, "problem finalizing server: %s", rp_string (retval)); | |
712 | |
713 for (i = 0; i < n; i++) | |
714 free ((char *) namelist[i]); | |
715 free ((char *) namelist); | |
716 | |
717 free ((char *) namelist); | |
718 | |
719 done (0); | |
720 } | |
721 #endif | |
722 #if defined(SYS5DIR) && !defined(BSD42) && !defined(hpux) && !defined(sgi) && !defined(linux) | |
723 /* | |
724 * Copyright (c) 1983 Regents of the University of California. | |
725 * All rights reserved. | |
726 * | |
727 * Redistribution and use in source and binary forms, with or without | |
728 * modification, are permitted provided that the following conditions | |
729 * are met: | |
730 * 1. Redistributions of source code must retain the above copyright | |
731 * notice, this list of conditions and the following disclaimer. | |
732 * 2. Redistributions in binary form must reproduce the above copyright | |
733 * notice, this list of conditions and the following disclaimer in the | |
734 * documentation and/or other materials provided with the distribution. | |
735 * 3. All advertising materials mentioning features or use of this software | |
736 * must display the following acknowledgement: | |
737 * This product includes software developed by the University of | |
738 * California, Berkeley and its contributors. | |
739 * 4. Neither the name of the University nor the names of its contributors | |
740 * may be used to endorse or promote products derived from this software | |
741 * without specific prior written permission. | |
742 * | |
743 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
744 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
745 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
746 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
747 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
748 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
749 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
750 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
751 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
752 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
753 * SUCH DAMAGE. | |
754 */ | |
755 #if defined(LIBC_SCCS) && !defined(lint) | |
756 static char sccsid[] = "@(#)scandir.c 5.10 (Berkeley) 2/23/91"; | |
757 #endif /* LIBC_SCCS and not lint */ | |
758 /* | |
759 * Scan the directory dirname calling select to make a list of selected | |
760 * directory entries then sort using qsort and compare routine dcomp. | |
761 * Returns the number of entries and a pointer to a list of pointers to | |
762 * struct dirent (through namelist). Returns -1 if there were any errors. | |
763 */ | |
764 /* | |
765 * This code modified by Ted Nolan to take Solaris dirent structures | |
766 * and mollify gcc -traditional. In general, everything from BSD that | |
767 * didn't work is "ifdef notdef" ed out | |
768 * | |
769 * 3 Feb 94 | |
770 */ | |
771 #include <sys/types.h> | |
772 #include <sys/stat.h> | |
773 #include <dirent.h> | |
774 /* #include <stdlib.h> */ | |
775 #include <string.h> | |
776 /* | |
777 * The DIRSIZ macro gives the minimum record length which will hold | |
778 * the directory entry. This requires the amount of space in struct dirent | |
779 * without the d_name field, plus enough space for the name with a terminating | |
780 * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. | |
781 */ | |
782 #undef DIRSIZ | |
783 #ifdef notdef | |
784 #define DIRSIZ(dp) \ | |
785 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) | |
786 #else | |
787 #define DIRSIZ(dp) \ | |
788 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + ((strlen(dp->d_name)+1 + 3) &~ 3)) | |
789 #endif | |
790 int | |
791 scandir(dirname, namelist, select, dcomp) | |
792 #ifdef notdef | |
793 const char *dirname; | |
794 #else | |
795 char *dirname; | |
796 #endif | |
797 struct dirent ***namelist; | |
798 #ifdef notdef | |
799 int (*select) __P((struct dirent *)); | |
800 int (*dcomp) __P((const void *, const void *)); | |
801 #else | |
802 int (*select)(); | |
803 int (*dcomp)(); | |
804 #endif | |
805 { | |
806 register struct dirent *d, *p, **names; | |
807 register size_t nitems; | |
808 struct stat stb; | |
809 long arraysz; | |
810 DIR *dirp; | |
811 if ((dirp = opendir(dirname)) == NULL) | |
812 return(-1); | |
813 if (stat(dirname, &stb) < 0) | |
814 return(-1); | |
815 /* | |
816 * estimate the array size by taking the size of the directory file | |
817 * and dividing it by a multiple of the minimum size entry. | |
818 */ | |
819 arraysz = (stb.st_size / 24); | |
820 names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *)); | |
821 if (names == NULL) | |
822 return(-1); | |
823 nitems = 0; | |
824 while ((d = readdir(dirp)) != NULL) { | |
825 if (select != NULL && !(*select)(d)) | |
826 continue; /* just selected names */ | |
827 /* | |
828 * Make a minimum size copy of the data | |
829 */ | |
830 p = (struct dirent *)malloc(DIRSIZ(d)); | |
831 if (p == NULL) | |
832 return(-1); | |
833 p->d_ino = d->d_ino; | |
834 p->d_reclen = d->d_reclen; | |
835 #ifdef notdef | |
836 p->d_namlen = d->d_namlen; | |
837 bcopy(d->d_name, p->d_name, p->d_namlen + 1); | |
838 #else | |
839 bcopy(d->d_name, p->d_name, strlen(p->d_name) + 1); | |
840 #endif | |
841 /* | |
842 * Check to make sure the array has space left and | |
843 * realloc the maximum size. | |
844 */ | |
845 if (++nitems >= arraysz) { | |
846 if (stat(dirname, &stb) < 0) | |
847 return(-1); /* just might have grown */ | |
848 arraysz = stb.st_size / 12; | |
849 names = (struct dirent **)realloc((char *)names, | |
850 arraysz * sizeof(struct dirent *)); | |
851 if (names == NULL) | |
852 return(-1); | |
853 } | |
854 names[nitems-1] = p; | |
855 } | |
856 closedir(dirp); | |
857 if (nitems && dcomp != NULL) | |
858 qsort(names, nitems, sizeof(struct dirent *), dcomp); | |
859 *namelist = names; | |
860 return(nitems); | |
861 } | |
862 /* | |
863 * Alphabetic order comparison routine for those who want it. | |
864 */ | |
865 int | |
866 alphasort(d1, d2) | |
867 #ifdef notdef | |
868 const void *d1; | |
869 const void *d2; | |
870 #else | |
871 char *d1; | |
872 char *d2; | |
873 #endif /* notdef */ | |
874 { | |
875 return(strcmp((*(struct dirent **)d1)->d_name, | |
876 (*(struct dirent **)d2)->d_name)); | |
877 } | |
878 #endif |