Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature-vt/sys/src/cmd/upas/send/main.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "common.h"
2
#include "send.h"
3
 
4
/* globals to all files */
5
int rmail;
6
char *thissys, *altthissys;
7
int nflg;
8
int xflg;
9
int debug;
10
int rflg;
11
int iflg = 1;
12
int nosummary;
13
 
14
/* global to this file */
15
static String *errstring;
16
static message *mp;
17
static int interrupt;
18
static int savemail;
19
static Biobuf in;
20
static int forked;
21
static int add822headers = 1;
22
static String *arglist;
23
 
24
/* predeclared */
25
static int	send(dest *, message *, int);
26
static void	lesstedious(void);
27
static void	save_mail(message *);
28
static int	complain_mail(dest *, message *);
29
static int	pipe_mail(dest *, message *);
30
static void	appaddr(String *, dest *);
31
static void	mkerrstring(String *, message *, dest *, dest *, char *, int);
32
static int	replymsg(String *, message *, dest *);
33
static int	catchint(void*, char*);
34
 
35
void
36
usage(void)
37
{
38
	fprint(2, "usage: mail [-birtx] list-of-addresses\n");
39
	exits("usage");
40
}
41
 
42
void
43
main(int argc, char *argv[])
44
{
45
	dest *dp=0;
46
	int checkforward;
47
	char *base;
48
	int rv;
49
 
50
	/* process args */
51
	ARGBEGIN{
52
	case '#':
53
		nflg = 1;
54
		break;
55
	case 'b':
56
		add822headers = 0;
57
		break;
58
	case 'x':
59
		nflg = 1;
60
		xflg = 1;
61
		break;
62
	case 'd':
63
		debug = 1;
64
		break;
65
	case 'i':
66
		iflg = 0;
67
		break;
68
	case 'r':
69
		rflg = 1;
70
		break;
71
	default:
72
		usage();
73
	}ARGEND
74
 
75
	while(*argv){
76
		if(shellchars(*argv)){
77
			fprint(2, "illegal characters in destination\n");
78
			exits("syntax");
79
		}
80
		d_insert(&dp, d_new(s_copy(*argv++)));
81
	}
82
 
83
	if (dp == 0)
84
		usage();
85
	arglist = d_to(dp);
86
 
87
	/*
88
	 * get context:
89
	 *	- whether we're rmail or mail
90
	 */
91
	base = basename(argv0);
92
	checkforward = rmail = (strcmp(base, "rmail")==0) | rflg;
93
	thissys = sysname_read();
94
	altthissys = alt_sysname_read();
95
	if(rmail)
96
		add822headers = 0;
97
 
98
	/*
99
	 *  read the mail.  If an interrupt occurs while reading, save in
100
	 *  dead.letter
101
	 */
102
	if (!nflg) {
103
		Binit(&in, 0, OREAD);
104
		if(!rmail)
105
			atnotify(catchint, 1);
106
		mp = m_read(&in, rmail, !iflg);
107
		if (mp == 0)
108
			exit(0);
109
		if (interrupt != 0) {
110
			save_mail(mp);
111
			exit(1);
112
		}
113
	} else {
114
		mp = m_new();
115
		if(default_from(mp) < 0){
116
			fprint(2, "%s: can't determine login name\n", argv0);
117
			exit(1);
118
		}
119
	}
120
	errstring = s_new();
121
	getrules();
122
 
123
	/*
124
	 *  If this is a gateway, translate the sender address into a local
125
	 *  address.  This only happens if mail to the local address is 
126
	 *  forwarded to the sender.
127
	 */
128
	gateway(mp);
129
 
130
	/*
131
	 *  Protect against shell characters in the sender name for
132
	 *  security reasons.
133
	 */
134
	mp->sender = escapespecial(mp->sender);
135
	if (shellchars(s_to_c(mp->sender)))
136
		mp->replyaddr = s_copy("postmaster");
137
	else
138
		mp->replyaddr = s_clone(mp->sender);
139
 
140
	/*
141
	 *  reject messages that have been looping for too long
142
	 */
143
	if(mp->received > 32)
144
		exit(refuse(dp, mp, "possible forward loop", 0, 0));
145
 
146
	/*
147
	 *  reject messages that are too long.  We don't do it earlier
148
	 *  in m_read since we haven't set up enough things yet.
149
	 */
150
	if(mp->size < 0)
151
		exit(refuse(dp, mp, "message too long", 0, 0));
152
 
153
	rv = send(dp, mp, checkforward);
154
	if(savemail)
155
		save_mail(mp);
156
	if(mp)
157
		m_free(mp);
158
	exit(rv);
159
}
160
 
161
/* send a message to a list of sites */
162
static int
163
send(dest *destp, message *mp, int checkforward)
164
{
165
	dest *dp;		/* destination being acted upon */
166
	dest *bound;		/* bound destinations */
167
	int errors=0;
168
 
169
	/* bind the destinations to actions */
170
	bound = up_bind(destp, mp, checkforward);
171
	if(add822headers && mp->haveto == 0){
172
		if(nosummary)
173
			mp->to = d_to(bound);
174
		else
175
			mp->to = arglist;
176
	}
177
 
178
	/* loop through and execute commands */
179
	for (dp = d_rm(&bound); dp != 0; dp = d_rm(&bound)) {
180
		switch (dp->status) {
181
		case d_cat:
182
			errors += cat_mail(dp, mp);
183
			break;
184
		case d_pipeto:
185
		case d_pipe:
186
			if (!rmail && !nflg && !forked) {
187
				forked = 1;
188
				lesstedious();
189
			}
190
			errors += pipe_mail(dp, mp);
191
			break;
192
		default:
193
			errors += complain_mail(dp, mp);
194
			break;
195
		}
196
	}
197
 
198
	return errors;
199
}
200
 
201
/* avoid user tedium (as Mike Lesk said in a previous version) */
202
static void
203
lesstedious(void)
204
{
205
	int i;
206
 
207
	if(debug)
208
		return;
209
 
210
	switch(fork()){
211
	case -1:
212
		break;
213
	case 0:
214
		sysdetach();
215
		for(i=0; i<3; i++)
216
			close(i);
217
		savemail = 0;
218
		break;
219
	default:
220
		exit(0);
221
	}
222
}
223
 
224
 
225
/* save the mail */
226
static void
227
save_mail(message *mp)
228
{
229
	Biobuf *fp;
230
	String *file;
231
 
232
	file = s_new();
233
	deadletter(file);
234
	fp = sysopen(s_to_c(file), "cAt", 0660);
235
	if (fp == 0)
236
		return;
237
	m_bprint(mp, fp);
238
	sysclose(fp);
239
	fprint(2, "saved in %s\n", s_to_c(file));
240
	s_free(file);
241
}
242
 
243
/* remember the interrupt happened */
244
 
245
static int
246
catchint(void *a, char *msg)
247
{
248
	USED(a);
249
	if(strstr(msg, "interrupt") || strstr(msg, "hangup")) {
250
		interrupt = 1;
251
		return 1;
252
	}
253
	return 0;
254
}
255
 
256
/* dispose of incorrect addresses */
257
static int
258
complain_mail(dest *dp, message *mp)
259
{
260
	char *msg;
261
 
262
	switch (dp->status) {
263
	case d_undefined:
264
		msg = "Invalid address"; /* a little different, for debugging */
265
		break;
266
	case d_syntax:
267
		msg = "invalid address";
268
		break;
269
	case d_unknown:
270
		msg = "unknown user";
271
		break;
272
	case d_eloop:
273
	case d_loop:
274
		msg = "forwarding loop";
275
		break;
276
	case d_noforward:
277
		if(dp->pstat && *s_to_c(dp->repl2))
278
			return refuse(dp, mp, s_to_c(dp->repl2), dp->pstat, 0);
279
		else
280
			msg = "destination unknown or forwarding disallowed";
281
		break;
282
	case d_pipe:
283
		msg = "broken pipe";
284
		break;
285
	case d_cat:
286
		msg = "broken cat";
287
		break;
288
	case d_translate:
289
		if(dp->pstat && *s_to_c(dp->repl2))
290
			return refuse(dp, mp, s_to_c(dp->repl2), dp->pstat, 0);
291
		else
292
			msg = "name translation failed";
293
		break;
294
	case d_alias:
295
		msg = "broken alias";
296
		break;
297
	case d_badmbox:
298
		msg = "corrupted mailbox";
299
		break;
300
	case d_resource:
301
		return refuse(dp, mp, "out of some resource.  Try again later.", 0, 1);
302
	default:
303
		msg = "unknown d_";
304
		break;
305
	}
306
	if (nflg) {
307
		print("%s: %s\n", msg, s_to_c(dp->addr));
308
		return 0;
309
	}
310
	return refuse(dp, mp, msg, 0, 0);
311
}
312
 
313
/* dispose of remote addresses */
314
static int
315
pipe_mail(dest *dp, message *mp)
316
{
317
	dest *next, *list=0;
318
	String *cmd;
319
	process *pp;
320
	int status, r;
321
	char *none;
322
	String *errstring=s_new();
323
 
324
	if (dp->status == d_pipeto)
325
		none = "none";
326
	else
327
		none = 0;
328
	/*
329
	 *  collect the arguments
330
	 */
331
	next = d_rm_same(&dp);
332
	if(xflg)
333
		cmd = s_new();
334
	else
335
		cmd = s_clone(next->repl1);
336
	for(; next != 0; next = d_rm_same(&dp)){
337
		if(xflg){
338
			s_append(cmd, s_to_c(next->addr));
339
			s_append(cmd, "\n");
340
		} else {
341
			if (next->repl2 != 0) {
342
				s_append(cmd, " ");
343
				s_append(cmd, s_to_c(next->repl2));
344
			}
345
		}
346
		d_insert(&list, next);
347
	}
348
 
349
	if (nflg) {
350
		if(xflg)
351
			print("%s", s_to_c(cmd));
352
		else
353
			print("%s\n", s_to_c(cmd));
354
		s_free(cmd);
355
		return 0;
356
	}
357
 
358
	/*
359
	 *  run the process
360
	 */
361
	pp = proc_start(s_to_c(cmd), instream(), 0, outstream(), 1, none);
362
	if(pp==0 || pp->std[0]==0 || pp->std[2]==0)
363
		return refuse(list, mp, "out of processes, pipes, or memory", 0, 1);
364
	pipesig(0);
365
	m_print(mp, pp->std[0]->fp, thissys, 0);
366
	pipesigoff();
367
	stream_free(pp->std[0]);
368
	pp->std[0] = 0;
369
	while(s_read_line(pp->std[2]->fp, errstring))
370
		;
371
	status = proc_wait(pp);
372
	proc_free(pp);
373
	s_free(cmd);
374
 
375
	/*
376
	 *  return status
377
	 */
378
	if (status != 0) {
379
		r = refuse(list, mp, s_to_c(errstring), status, 0);
380
		s_free(errstring);
381
		return r;
382
	}
383
	s_free(errstring);
384
	loglist(list, mp, "remote");
385
	return 0;
386
}
387
 
388
static void
389
appaddr(String *sp, dest *dp)
390
{
391
	dest *parent;
392
	String *s;
393
 
394
	if (dp->parent != 0) {
395
		for(parent=dp->parent; parent->parent!=0; parent=parent->parent)
396
			;
397
		s = unescapespecial(s_clone(parent->addr));
398
		s_append(sp, s_to_c(s));
399
		s_free(s);
400
		s_append(sp, "' alias `");
401
	}
402
	s = unescapespecial(s_clone(dp->addr));
403
	s_append(sp, s_to_c(s));
404
	s_free(s);
405
}
406
 
407
/*
408
 *  reject delivery
409
 *
410
 *  returns	0	- if mail has been disposed of
411
 *		other	- if mail has not been disposed
412
 */
413
int
414
refuse(dest *list, message *mp, char *cp, int status, int outofresources)
415
{
416
	String *errstring=s_new();
417
	dest *dp;
418
	int rv;
419
 
420
	dp = d_rm(&list);
421
	mkerrstring(errstring, mp, dp, list, cp, status);
422
 
423
	/*
424
	 *  log first in case we get into trouble
425
	 */
426
	logrefusal(dp, mp, s_to_c(errstring));
427
 
428
	/*
429
	 *  bulk mail is never replied to, if we're out of resources,
430
	 *  let the sender try again
431
	 */
432
	if(rmail){
433
		/* accept it or request a retry */
434
		if(outofresources){
435
			fprint(2, "Mail %s\n", s_to_c(errstring));
436
			rv = 1;					/* try again later */
437
		} else if(mp->bulk)
438
			rv = 0;					/* silently discard bulk */
439
		else
440
			rv = replymsg(errstring, mp, dp);	/* try later if we can't reply */
441
	} else {
442
		/* aysnchronous delivery only happens if !rmail */
443
		if(forked){
444
			/*
445
			 *  if spun off for asynchronous delivery, we own the mail now.
446
			 *  return it or dump it on the floor.  rv really doesn't matter.
447
			 */
448
			rv = 0;
449
			if(!outofresources && !mp->bulk)
450
				replymsg(errstring, mp, dp);
451
		} else {
452
			fprint(2, "Mail %s\n", s_to_c(errstring));
453
			savemail = 1;
454
			rv = 1;
455
		}
456
	}
457
 
458
	s_free(errstring);
459
	return rv;
460
}
461
 
462
/* make the error message */
463
static void
464
mkerrstring(String *errstring, message *mp, dest *dp, dest *list, char *cp, int status)
465
{
466
	dest *next;
467
	char smsg[64];
468
	String *sender;
469
 
470
	sender = unescapespecial(s_clone(mp->sender));
471
 
472
	/* list all aliases */
473
	s_append(errstring, " from '");
474
	s_append(errstring, s_to_c(sender));
475
	s_append(errstring, "'\nto '");
476
	appaddr(errstring, dp);
477
	for(next = d_rm(&list); next != 0; next = d_rm(&list)) {
478
		s_append(errstring, "'\nand '");
479
		appaddr(errstring, next);
480
		d_insert(&dp, next);
481
	}
482
	s_append(errstring, "'\nfailed with error '");
483
	s_append(errstring, cp);
484
	s_append(errstring, "'.\n");
485
 
486
	/* >> and | deserve different flavored messages */
487
	switch(dp->status) {
488
	case d_pipe:
489
		s_append(errstring, "The mailer `");
490
		s_append(errstring, s_to_c(dp->repl1));
491
		sprint(smsg, "' returned error status %x.\n\n", status);
492
		s_append(errstring, smsg);
493
		break;
494
	}
495
 
496
	s_free(sender);
497
}
498
 
499
/*
500
 *  create a new boundary
501
 */
502
static String*
503
mkboundary(void)
504
{
505
	char buf[32];
506
	int i;
507
	static int already;
508
 
509
	if(already == 0){
510
		srand((time(0)<<16)|getpid());
511
		already = 1;
512
	}
513
	strcpy(buf, "upas-");
514
	for(i = 5; i < sizeof(buf)-1; i++)
515
		buf[i] = 'a' + nrand(26);
516
	buf[i] = 0;
517
	return s_copy(buf);
518
}
519
 
520
/*
521
 *  reply with up to 1024 characters of the
522
 *  original message
523
 */
524
static int
525
replymsg(String *errstring, message *mp, dest *dp)
526
{
527
	message *refp = m_new();
528
	dest *ndp;
529
	char *rcvr;
530
	int rv;
531
	String *boundary;
532
 
533
	boundary = mkboundary();
534
 
535
	refp->bulk = 1;
536
	refp->rfc822headers = 1;
537
	rcvr = dp->status==d_eloop ? "postmaster" : s_to_c(mp->replyaddr);
538
	ndp = d_new(s_copy(rcvr));
539
	s_append(refp->sender, "postmaster");
540
	s_append(refp->replyaddr, "/dev/null");
541
	s_append(refp->date, thedate());
542
	refp->haveto = 1;
543
	s_append(refp->body, "To: ");
544
	s_append(refp->body, rcvr);
545
	s_append(refp->body, "\n");
546
	s_append(refp->body, "Subject: bounced mail\n");
547
	s_append(refp->body, "MIME-Version: 1.0\n");
548
	s_append(refp->body, "Content-Type: multipart/mixed;\n");
549
	s_append(refp->body, "\tboundary=\"");
550
	s_append(refp->body, s_to_c(boundary));
551
	s_append(refp->body, "\"\n");
552
	s_append(refp->body, "Content-Disposition: inline\n");
553
	s_append(refp->body, "\n");
554
	s_append(refp->body, "This is a multi-part message in MIME format.\n");
555
	s_append(refp->body, "--");
556
	s_append(refp->body, s_to_c(boundary));
557
	s_append(refp->body, "\n");
558
	s_append(refp->body, "Content-Disposition: inline\n");
559
	s_append(refp->body, "Content-Type: text/plain; charset=\"US-ASCII\"\n");
560
	s_append(refp->body, "Content-Transfer-Encoding: 7bit\n");
561
	s_append(refp->body, "\n");
562
	s_append(refp->body, "The attached mail");
563
	s_append(refp->body, s_to_c(errstring));
564
	s_append(refp->body, "--");
565
	s_append(refp->body, s_to_c(boundary));
566
	s_append(refp->body, "\n");
567
	s_append(refp->body, "Content-Type: message/rfc822\n");
568
	s_append(refp->body, "Content-Disposition: inline\n\n");
569
	s_append(refp->body, s_to_c(mp->body));
570
	s_append(refp->body, "--");
571
	s_append(refp->body, s_to_c(boundary));
572
	s_append(refp->body, "--\n");
573
 
574
	refp->size = s_len(refp->body);
575
	rv = send(ndp, refp, 0);
576
	m_free(refp);
577
	d_free(ndp);
578
	return rv;
579
}