"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "tulp-4.2.1/src/l.c" of archive tulp-4.2.1.tar.gz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 /*
2 * TULP - Unix Mailing List manager
3 * (sub-set of FRECP's Bitnet Listserv tool)
4 *
5 * Copyright (C) 1991-2000 Kimmo Suominen, Christophe Wolfhugel
6 *
7 * Please read the files COPYRIGHT and AUTHORS for the extended
8 * copyrights refering to this file.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 1, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <signal.h>
28 #include <dirent.h>
29 #include <time.h>
30 #include <unistd.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <sys/ioctl.h>
34 #include <sys/param.h>
35 #include <sys/times.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include "conf.h"
39 #include "ext.h"
40 #include "lp.h"
41 #include "str.h"
42 #include "popen.h"
43 #include "ad.h"
44 #include "lc.h"
45 #include "messages.h"
46 #ifdef FAKESYSLOG
47 # include "fakesyslog.h"
48 #else
49 # include <syslog.h>
50 #endif /* FAKESYSLOG */
51
52 RCSID("@(#)l.c,v 1.15 2000/03/07 22:16:29 kim Exp")
53
54 int Debug = 0;
55
56 short subj;
57
58 int done = 0;
59 char listName[256], fname[256];
60 char From[MAXLINE], To[MAXLINE], ReplyTo[MAXLINE], Approved[MAXLINE];
61 char buf[MAXLINE], rcpt[MAXFIELD];
62 int d, h, m, s;
63 long startTime, endTime, msgSize;
64 struct tms t;
65
66 static int ctr;
67
68 void lTodhms(long t)
69 {
70 d = t / (24 * 3600L);
71 h = (t % (24 * 3600L)) / 3600;
72 m = (t % 3600) / 60;
73 s = t % 60;
74 }
75
76 char *instring(char *s1, char *s2)
77 {
78 if ((int) strlen(s2) > (int) strlen(s1))
79 return (NULL);
80 for (; *(s1 + strlen(s2) - 1); s1++)
81 if (strncasecmp(s1, s2, strlen(s2)) == 0)
82 return (s1);
83 return (NULL);
84 }
85
86 char *strlwr(char *s)
87 {
88 char *p = s;
89
90 if (s == NULL)
91 return (NULL);
92 for (; *s; s++)
93 *s = tolower(*s);
94 return (p);
95 }
96
97 char *strupr(char *s)
98 {
99 char *p = s;
100
101 if (s == NULL)
102 return (NULL);
103 for (; *s; s++)
104 *s = toupper(*s);
105 return (p);
106 }
107
108 void pruneHeader(FILE *f, FILE *h)
109 {
110 char cmd[MAXFIELD + 256], *p;
111 int c;
112
113 while (fgets(cmd, sizeof(cmd), f) != NULL && cmd[0] != '\n') {
114 /* if the line is too long, throw the rest away */
115 if (strchr(cmd, '\n') == NULL) {
116 while ((c = getc(f)) != '\n' && c != EOF)
117 continue;
118 }
119 while ((c = getc(f)) == ' ' || c == '\t') {
120 p = &cmd[strlen(cmd)];
121 *p++ = ' ';
122 if (fgets(p, sizeof(cmd) - (p - cmd), f) == NULL)
123 break;
124 }
125 if (!feof(f) && !ferror(f))
126 ungetc(c, f);
127
128 /* We weed out all Resent- headers not to confuse MTAs */
129 if (strncasecmp(cmd, "Resent-", 7) == 0)
130 continue;
131 /* We use Comments for our purposes */
132 if (strncasecmp(cmd, "Comments: ", 10) == 0)
133 continue;
134 /* Prevent messages from showing up as "old" for recipients */
135 if (strncasecmp(cmd, "Status: ", 8) == 0)
136 continue;
137 /* We will be putting in our own Precedence header */
138 if (strncasecmp(cmd, "Precedence: ", 12) == 0)
139 continue;
140 if (strncasecmp(cmd, "X-Envelope-To: ", 15) == 0)
141 continue;
142 /* This is our internal header, do not forward it */
143 if (strncasecmp(cmd, "X-Listserv-To: ", 15) == 0)
144 continue;
145 /* Broken mailer or deliver script seen somewhere */
146 if (strncasecmp(cmd, ">From ", 6) == 0)
147 continue;
148 /* No, don't ack everyone to our request person */
149 if (strncasecmp(cmd, "Return-Receipt-To: ", 19) == 0)
150 continue;
151 /*
152 * X.400 loop detection is looking at these headers. We remove
153 * them to allow copies to be distributed to users behind X.400.
154 * The stupid systems will bounce messages if they originated on
155 * or behind the gateway thus preventing anyone anywhere on X.400
156 * from getting their copy of the message.
157 */
158 if (strncasecmp(cmd, "X400-Received: ", 15) == 0)
159 continue;
160 #ifdef STRIP_RECEIVED
161 /* Prevent loop detection */
162 if (strncasecmp(cmd, "Received: ", 10) == 0)
163 continue;
164 #endif
165 if (ReplyTo[0] != 0 && strncasecmp(cmd, "Reply-To: ", 10) == 0)
166 continue;
167 if (*GetErrorsTo() != '\0' && strncasecmp(cmd, "Errors-To: ", 11) == 0)
168 continue;
169 #ifdef ADD_SENDER
170 if (strncasecmp(cmd, "Sender: ", 8) == 0)
171 continue;
172 #endif
173 fputs(cmd, h);
174 }
175 fputs("Precedence: list\n", h);
176 #ifdef ADD_SENDER
177 fputs(versSender, h);
178 #endif
179 }
180
181 void mailMsg(char *to, char *subj)
182 {
183 FILE *f, *g;
184 char cmd[MAXLINE + 256];
185
186 if ((f = fopen(fname, "r")) == NULL) {
187 syslog(LOG_ERR, "mailMsg - fopen failed: %m");
188 exit(2);
189 }
190 g = getMTA(to, "listserv", MTA_MAIL);
191 fprintf(g, "To: %s\n", to);
192 fprintf(g, "Subject: %s\n", subj);
193 fprintf(g, "\n------- Forwarded message follows -------\n\n");
194 while (fgets(cmd, sizeof(cmd), f) != NULL) {
195 if (cmd[0] == '-') {
196 fprintf(g, "- ");
197 }
198 fputs(cmd, g);
199 }
200 fprintf(g, "\n------- End of forwarded message -------\n");
201 l_pclose(g);
202 fclose(f);
203 }
204
205 void resendMsg(char *to, char *comment)
206 {
207 FILE *f, *g;
208 char cmd[MAXLINE + 256];
209
210 if ((f = fopen(fname, "r")) == NULL) {
211 syslog(LOG_ERR, "resendMsg - fopen failed: %m");
212 exit(2);
213 }
214 g = getMTA(to, "listserv", MTA_RESEND);
215 pruneHeader(f, g);
216 fprintf(g, "Resent-To: %s\n", to);
217 fprintf(g, "Comments: %s\n", comment);
218 fprintf(g, "\n");
219 while (fgets(cmd, sizeof(cmd), f) != NULL) {
220 fputs(cmd, g);
221 }
222 fclose(f);
223 l_pclose(g);
224 }
225
226 void sendMsg()
227 {
228 char cmd[MAXFIELD + 256];
229 FILE *f, *g;
230
231 if ((f = fopen(fname, "r")) == NULL) {
232 syslog(LOG_ERR, "sendMsg - fopen failed: %m");
233 exit(2);
234 }
235 g = getMTA(rcpt, listName, MTA_RELAY);
236 pruneHeader(f, g);
237 if (*GetErrorsTo() != '\0')
238 fprintf(g, "Errors-To: %s\n", GetErrorsTo());
239 if (ReplyTo[0] != 0)
240 fprintf(g, "Reply-To: %s\n", ReplyTo);
241 if (subj == 0)
242 fprintf(g, "Subject: <none>\n");
243 if (ctr != 0)
244 fprintf(g, "X-Sequence: %d\n", ctr);
245 fprintf(g, "\n");
246 while (fgets(cmd, sizeof(cmd), f) != NULL) {
247 fputs(cmd, g);
248 }
249 fclose(f);
250 l_pclose(g);
251 }
252
253 void saveMsg()
254 {
255 FILE *f, *g;
256 long ti;
257 struct tm *t;
258 int dir = 0, oldfile = 0;
259 char cmd[64];
260 struct stat st;
261
262 time(&ti);
263 t = localtime(&ti);
264 f = fopen(fname, "r");
265 if (chdir(listName) == -1) {
266 fclose(f);
267 return;
268 } else {
269 dir = 1;
270 sprintf(cmd, "log%04d%02d", t->tm_year + 1900, t->tm_mon + 1);
271 oldfile = stat(cmd, &st) + 1;
272 g = fopen(cmd, "a");
273 }
274 if (!oldfile) {
275 fprintf(g, "This digest for list %s has been created on %s\n\n",
276 listName, asctime(t));
277 fputs("------- THIS IS A RFC934 COMPLIANT DIGEST, YOU CAN BURST IT -------\n\n", g);
278 }
279 while (fgets(buf, sizeof(buf), f) != NULL && buf[0] != '\n') {
280 if (strncmp(buf, "Subject:", 8) == 0 || strncmp(buf, "Date:", 5) == 0)
281 fputs(buf, g);
282 if (strncmp(buf, "From:", 5) == 0) {
283 fprintf(g, "From: %s\n", From);
284 if (subj == 0)
285 fprintf(g, "Subject: <none>\n");
286 }
287 strlwr(buf);
288 }
289 if (ctr != 0)
290 fprintf(g, "X-Sequence: %d\n", ctr);
291 do {
292 if (buf[0] == '-') {
293 fprintf(g, "- ");
294 }
295 fputs(buf, g);
296 } while (fgets(buf, sizeof(buf), f) != NULL);
297 fputs("------- CUT --- CUT --- CUT --- CUT --- CUT --- CUT --- CUT -------\n\n", g);
298 fclose(f);
299 fclose(g);
300 if (dir == 1)
301 chdir(TULPDIR);
302 }
303
304 void reqMsg()
305 {
306 char cmd[128];
307
308 strcpy(listName, To);
309 if (ReadUserList(listName) == -1) {
310 syslog(LOG_INFO, "Sending error (list not found)");
311 mailMsg("listman", "List not found");
312 } else {
313 syslog(LOG_INFO, "List %s - Request from %s forwarded", listName, From);
314 RewindOwnerList();
315 while (GetOwner(cmd) != NULL)
316 resendMsg(strtok(cmd, " \t\r\n"), "Request mail");
317 CloseUserList();
318 }
319 unlink(fname);
320 }
321
322 void fwdMsg()
323 {
324 FILE *f, *g, *h;
325 int i;
326 char *p;
327 char cmd[128];
328
329 strcpy(listName, To);
330 if (ReadUserList(listName) == -1) {
331 syslog(LOG_INFO, "Sending error (list not found)");
332 mailMsg("listman", "List not found");
333 unlink(fname);
334 return;
335 }
336 strcpy(buf, GetReplyTo());
337 if (ReplyTo[0] == 0 || instring(buf, ",respect") == NULL) {
338 if (strncasecmp(buf, "list", 4) == 0) {
339 strcpy(cmd, listName);
340 strupr(cmd);
341 sprintf(ReplyTo, "%s Distribution List <%s@%s>", cmd, listName, HOST);
342 } else if (strncasecmp(buf, "sender", 6) != 0)
343 sprintf(ReplyTo, "%s", strtok(buf, ","));
344 }
345 RewindUserList();
346 if (strcasecmp(GetSend(), "private") == 0 && !IsUser(From)) {
347 syslog(LOG_INFO,
348 "Mail to list %s from %s - Refused, this user is not allowed",
349 listName, From);
350 sprintf(buf, "%s %s", SENDMAIL, strtok(From, " ")); /* NAK to sender */
351 if ((g = l_popen(buf, "w")) == NULL) {
352 syslog(LOG_ERR, "fwdMsg - popen failed: %m");
353 unlink(fname);
354 CloseUserList();
355 return;
356 }
357 if ((f = fopen(fname, "r")) == NULL) {
358 syslog(LOG_ERR, "fwdMsg - fopen failed: %m");
359 unlink(fname);
360 CloseUserList();
361 return;
362 }
363 fprintf(g, TULP_HDRMAILNAK(From, listName));
364 fprintf(g, TULP_MAILPRIVATE);
365 while (fgets(buf, sizeof(buf), f) != NULL) /* unsent message */
366 fputs(buf, g);
367 l_pclose(g);
368 fclose(f);
369 RewindOwnerList();
370 while (GetOwner(buf) != NULL)
371 mailMsg(strtok(buf, " \t\r\n"), "Sent by a non-subscriber");
372 } else if (strcasecmp(GetSend(), "editor") == 0
373 && !IsEditor(Approved) && !IsEditor(From)) {
374 syslog(LOG_INFO, "Mail to list %s from %s - Article to moderate",
375 listName, From);
376 RewindEditorList();
377 while (GetEditor(buf) != NULL)
378 mailMsg(strtok(buf, " \t\r\n"), "Article to moderate");
379 } else { /* Ok to send */
380 strcpy(buf, listName); /* X-Sequence - update listName.n */
381 strcat(buf, ".n");
382 ctr = 0;
383 h = fopen(buf, "r+");
384 if (h != NULL) {
385 fscanf(h, "%d", &ctr);
386 rewind(h);
387 fprintf(h, "%d\n", ++ctr);
388 fclose(h);
389 }
390 syslog(LOG_INFO, "List %s - Msg from %s accepted", listName, From);
391 saveMsg(); /* save Msg in log file */
392 i = 0;
393 p = rcpt;
394 while (GetUser(buf) != NULL) {
395 strtok(buf, "\t\r\n ");
396 if ((((p - rcpt) + strlen(buf) + 2) > sizeof(rcpt))
397 || (i++ > BATCHSIZE - 1)) {
398 i = 1;
399 p = rcpt;
400 sendMsg();
401 }
402 sprintf(p, "%s ", buf);
403 p += strlen(p);
404 }
405 if (i != 0)
406 sendMsg();
407 }
408 unlink(fname);
409 CloseUserList();
410 }
411
412 int copyMail(char *file)
413 {
414 FILE *h;
415 char *p;
416 int c;
417 struct stat st;
418
419 if ((h = fopen(file, "r")) == NULL)
420 return (-1);
421 To[0] = 0;
422 fstat(fileno(h), &st);
423 msgSize = st.st_size;
424 subj = 0;
425 To[0] = ReplyTo[0] = Approved[0] = 0;
426 while (fgets(buf, sizeof(buf), h) != NULL && buf[0] != '\n') {
427 /* if the line is too long, throw the rest away */
428 if (strchr(buf, '\n') == NULL) {
429 while ((c = getc(h)) != '\n' && c != EOF)
430 continue;
431 }
432 while ((c = getc(h)) == ' ' || c == '\t') {
433 p = &buf[strlen(buf) - 1];
434 *p++ = ' ';
435 if (fgets(p, sizeof(buf) - (p - buf), h) == NULL)
436 break;
437 }
438 if (!feof(h) && !ferror(h))
439 ungetc(c, h);
440 strtok(buf, "\n");
441 if (Debug)
442 fprintf(stderr, "Collected line: %s\n", buf);
443 if (strlen(buf) > MAXLINE) {
444 syslog(LOG_ERR, "Header line too long: %s", strtok(buf, ":"));
445 fclose(h);
446 return (-2);
447 }
448 if (strncmp(buf, "Reply-To: ", 10) == 0)
449 strcpy(ReplyTo, buf + 10);
450 if (strncmp(buf, "Subject: ", 9) == 0) {
451 /* We could save subject here, but we don't need it */
452 subj = 1;
453 continue;
454 }
455 if (strncmp(buf, "From: ", 6) == 0) {
456 /* Usually just one author */
457 strcpy(From, buf + 6);
458 continue;
459 }
460 if (strncmp(buf, "Approved: ", 10) == 0) {
461 strcpy(Approved, buf + 10);
462 continue;
463 }
464 if (strncmp(buf, "X-Listserv-To: ", 15) == 0) {
465 strcpy(To, buf + 15);
466 continue;
467 }
468 }
469 adChange(From);
470 strlwr(To);
471 fclose(h);
472 if (To[0] == 0) {
473 syslog(LOG_ERR, "X-Listserv-To is empty or not found");
474 return (-2);
475 }
476 return (0);
477 }
478
479 void sTe()
480 {
481 done = 1;
482 }
483
484 void main(int argn, char **argv)
485 {
486 struct sigaction sa;
487 int i;
488 long clk_tck;
489 char *p;
490 extern void reapchild();
491 DIR *qdir;
492 struct dirent *qfile;
493
494 while ((i = getopt(argn, argv, "d")) != EOF) {
495 switch (i) {
496 case 'd':
497 Debug = 1;
498 break;
499 default:
500 fprintf(stderr, "usage: %s [-d]\n", *argv);
501 exit(1);
502 }
503 }
504 if (chdir(TULPDIR) == -1) {
505 perror("Can't chdir' to TULPDIR. Aborting.");
506 exit(2);
507 }
508 versInit();
509 setbuf(stdout, NULL);
510 printf("%s: daemon started for %s\n\r", vers, HOST);
511 printf("Copyright (C) 1991-1997 Kimmo Suominen, Christophe Wolfhugel\n");
512 printf("Listserv comes with ABSOLUTELY NO WARRANTY; for details see\n");
513 printf("the GNU General Public License that is furnished with the\n");
514 printf("sources of this package.\n");
515 if (Debug == 0)
516 if (fork())
517 exit(0); /* Dissociate us from tty */
518 times(&t);
519 time(&startTime);
520 nice(NICENESS);
521 if (Debug == 0) {
522 freopen("/dev/null", "w", stdout);
523 freopen("/dev/null", "w", stderr);
524 close(fileno(stdin));
525 setpgid(0, 0);
526 }
527 sigemptyset(&sa.sa_mask);
528 #ifdef SA_RESTART
529 sa.sa_flags = SA_RESTART; /* Restart system calls? SA_RESTART */
530 /* Children? SA_NOCLDWAIT, SA_NOCLDSTOP */
531 #else
532 sa.sa_flags = 0;
533 #endif
534 sa.sa_handler = sTe;
535 sigaction(SIGTERM, &sa, NULL);
536 #ifdef SIGURGENT
537 sigaction(SIGURGENT, &sa, NULL);
538 #endif
539 sa.sa_handler = SIG_IGN;
540 /* SA_RESETHAND: Reset to SIG_DFL, not blocked */
541 /* sa.sa_flags = SA_RESETHAND; */
542 sa.sa_handler = reapchild;
543 sigaction(SIGCHLD, &sa, NULL);
544 umask(022);
545 openlog("listserv", LOG_PID, LOG_MAIL);
546 syslog(LOG_INFO, "Listserv Started");
547 umask(077);
548 while (!done) {
549 qdir = opendir(QUEUEDIR);
550 if (qdir == NULL) {
551 syslog(LOG_CRIT, "Failed to open Qdir");
552 exit(1);
553 }
554 while (!done && (qfile = readdir(qdir)) != NULL) {
555 if (qfile->d_name[0] < '0' || qfile->d_name[0] > '9')
556 continue;
557 sprintf(fname, "%s/%s", QUEUEDIR, qfile->d_name);
558 if ((i = copyMail(fname)) == -1)
559 continue;
560 if (i == -2) {
561 mailMsg("listman", "Unknown error, see syslog");
562 unlink(fname);
563 continue;
564 }
565 if ((strcmp(To, "listman") == 0) ||
566 (strcmp(To, "postmaster") == 0) ||
567 (strcmp(To, "listserv-request") == 0)) {
568 syslog(LOG_INFO, "Mail for ListMan");
569 resendMsg("listman", "Mail for ListMan");
570 unlink(fname);
571 continue;
572 }
573 if (((p = strrchr(To, '-')) != NULL) && (strcmp(p, "-request") == 0)) {
574 *p = '\0';
575 reqMsg();
576 continue;
577 }
578 if (instring(From, "mailer-") != NULL ||
579 instring(From, "mailer@") != NULL ||
580 instring(From, "postmaster@") != NULL ||
581 instring(From, "listserv@") != NULL ||
582 instring(From, "root@") != NULL ||
583 instring(From, "system@") != NULL ||
584 instring(From, "-request@") != NULL ||
585 instring(From, "owner-") != NULL) {
586 syslog(LOG_INFO, "Message from Mailer-Daemon");
587 mailMsg("listman", "Message from Mailer-Daemon");
588 unlink(fname);
589 continue;
590 }
591 if (strcmp(To, "listserv") == 0) {
592 listservCmd(fname);
593 continue;
594 }
595 fwdMsg();
596 }
597 closedir(qdir);
598 sleep(60);
599 }
600 clk_tck = sysconf(_SC_CLK_TCK);
601 if (clk_tck < 0) {
602 syslog(LOG_ERR, "Could not get CLK_TCK, defaulting to 100\n");
603 syslog(LOG_ERR, "sysconf(_SC_CLK_TCK): %s\n", strerror(errno));
604 clk_tck = 100;
605 }
606 syslog(LOG_INFO, "Listserv has been terminated");
607 time(&endTime);
608 lTodhms(endTime - startTime);
609 times(&t);
610 t.tms_utime += t.tms_cutime;
611 t.tms_stime += t.tms_cstime;
612 syslog(LOG_INFO, "Total elapsed time: +%dd %02d:%02d:%02d\n", d, h, m, s);
613 lTodhms(t.tms_utime / clk_tck);
614 syslog(LOG_INFO, "User CPU time: +%dd %02d:%02d:%02d\n", d, h, m, s);
615 lTodhms(t.tms_stime / clk_tck);
616 syslog(LOG_INFO, "System CPU time: +%dd %02d:%02d:%02d\n", d, h, m, s);
617 lTodhms((t.tms_utime += t.tms_stime) / clk_tck);
618 syslog(LOG_INFO, "Total CPU time: +%dd %02d:%02d:%02d\n", d, h, m, s);
619 syslog(LOG_INFO, "%% CPU used: %02.02f%%\n",
620 (float) (t.tms_utime / clk_tck * 100) / (float) (endTime - startTime + 1));
621 closelog();
622 exit(0);
623 }