1;# $Id$
2;#
3;#  Copyright (c) 1990-2006, Raphael Manfredi
4;#
5;#  You may redistribute only under the terms of the Artistic License,
6;#  as specified in the README file that comes with the distribution.
7;#  You may reuse parts of this distribution only within the terms of
8;#  that same Artistic License; a copy of which may be found at the root
9;#  of the source tree for mailagent 3.0.
10;#
11;# $Log: sendfile.pl,v $
12;# Revision 3.0.1.3  1995/02/16  14:36:59  ram
13;# patch32: indentation fix
14;#
15;# Revision 3.0.1.2  1994/10/10  10:25:40  ram
16;# patch19: added various escapes in strings for perl5 support
17;#
18;# Revision 3.0.1.1  1994/10/04  17:55:43  ram
19;# patch17: now uses the email config parameter to send messages to user
20;#
21;# Revision 3.0  1993/11/29  13:49:16  ram
22;# Baseline for mailagent 3.0 netwide release.
23;#
24;#
25;# This file contains two subroutines:
26;#   - sendfile, sends a set of files
27;#   - abort, called when something got wrong
28;#
29;# A routine clean_tmp must be defined in the program, for removing
30;# possible temporary files in case abort is called.
31;#
32# Send a set of files
33sub sendfile {
34	local($dest, $cf'tmpdir, $pack, $subject) = @_;
35	&add_log("sending dir $cf'tmpdir to $dest, mode $pack") if $loglvl > 9;
36
37	# A little help message
38	local($mail_help) = "Detailed intructions can be obtained by:
39
40	Subject: Command
41	\@SH mailhelp $dest";
42
43	# Go to tmpdir where files are stored
44	chdir $cf'tmpdir || &abort("NO TMP DIRECTORY");
45
46	# Build a list of files to send
47	local($list) = "";		# List of plain files
48	local($dlist) = "";		# List with directories (for makekit)
49	local($nbyte) = 0;
50	local($nsend) = 0;
51	open(FIND, "find . -print |") || &abort("CANNOT RUN FIND");
52	while (<FIND>) {
53		chop;
54		next if $_ eq '.';		# Skip current directory `.'
55		s|^\./||;
56		$dlist .= $_ . " ";		# Save file/dir name
57		if (-f $_) {			# If plain file
58			$list .= $_ . " ";	# Save plain file
59			$nsend++;			# One more file to send
60			($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
61				$blksize,$blocks) = stat($_);
62			$nbyte += $size;	# Update total size
63		}
64	}
65	close FIND;
66
67	&abort("NO FILE TO SEND") unless $nsend;
68	if ($nsend > 1) {
69		&add_log("$nsend files to pack ($nbyte bytes)") if $loglvl > 9;
70	} else {
71		&add_log("1 file to pack ($nbyte bytes)") if $loglvl > 9;
72	}
73
74	# Pack files
75	if ($pack =~ /kit/) {
76		system "kit -n Part $list" || &abort("CANNOT KIT FILES");
77		$packed = "kit";
78	} elsif ($pack =~ /shar/) {
79		# Create a manifest, so that we can easily run maniscan
80		# Leave a PACKNOTES file with non-zero length if problems.
81		local($mani) = $dlist;
82		$mani =~ s/ /\n/g;
83		local($packlist) = "pack.$$";	# Pack list used as manifest
84		if (open(PACKLIST, ">$packlist")) {
85			print PACKLIST $mani;
86			close PACKLIST;
87			system 'maniscan', "-i$packlist",
88				"-o$packlist", '-w0', '-n', '-lPACKNOTES';
89			&add_log("ERROR maniscan returned non-zero status")
90				if $loglvl > 5 && $?;
91			if (-s 'PACKNOTES') {		# Files split or uu-encoded
92				system 'makekit', "-i$packlist", '-t',
93					"Now run 'sh PACKNOTES'." || &abort("CANNOT SHAR FILES");
94			} else {
95				system 'makekit', "-i$packlist" || &abort("CANNOT SHAR FILES");
96			}
97		} else {
98			&add_log("ERROR cannot create packlist") if $loglvl > 5;
99			system "makekit $dlist" || &abort("CANNOT SHAR FILES");
100		}
101		$packed = "shar";
102	} else {
103		if ($nbyte > $cf'maxsize) {		# Defined in ~/.mailagent
104			system "kit -M -n Part $list" || &abort("CANNOT KIT FILES");
105			$packed = "minikit";		# The minikit is included
106		} else {
107			# Try with makekit first
108			if (system "makekit $dlist") {	# If failed
109				system "kit -M -n Part $list" || &abort("CANNOT KIT FILES");
110				$packed = "minikit";	# The minikit is included
111			} else {
112				$packed = "shar";
113			}
114		}
115	}
116
117	# How many parts are there ?
118	@parts = <Part*>;
119	$npart = $#parts + 1;		# Number of parts made
120	&abort("NO PART TO SEND -- $packed failed") unless $npart;
121	if ($npart > 1) {
122		&add_log("$npart $packed parts to send") if $loglvl > 19;
123	} else {
124		&add_log("$npart $packed part to send") if $loglvl > 19;
125	}
126
127	# Now send the parts
128	$nbyte = 0;				# How many bytes do we send ?
129	$part_num = 0;
130	$signal="";				# To signal parts number if more than 1
131	local($partsent) = 0;	# Number of parts actually sent
132	local($bytesent) = 0;	# Amount of bytes actually sent
133	foreach $part (@parts) {
134		($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
135			$blksize,$blocks) = stat($part);
136		$nbyte += $size;	# Update total size
137
138		&add_log("dealing with $part ($size bytes)") if $loglvl > 19;
139
140		# See if we need to signal other parts
141		$part_num++;			# Update part number
142		if ($npart > 1) {
143			$signal=" (Part $part_num/$npart)";
144		}
145
146		# Send part
147		open(MAILER, "|$cf'sendmail $cf'mailopt $dest");
148		print MAILER
149"To: $dest
150Subject: $subject$signal
151Precedence: bulk
152X-Mailer: mailagent [version $mversion-$revision]
153
154Here is the answer to your request:
155
156	$fullcmd
157
158
159";
160		if ($packed eq 'minikit') {		# Kit with minikit included
161			print MAILER
162"This is a kit file. It will be simpler to unkit it if you own the kit
163package (latest patchlevel), but you can use the minikit provided with
164this set of file (please see instructions provided by kit itself at the
165head of each part). If you wish to get kit, send me the following mail:
166
167";
168		} elsif ($packed eq 'kit') {	# Plain kit files
169			print MAILER
170"This is a kit file. You need the kit package (latest patchlevel) to
171unkit it. If you do not have kit, send me the following mail:
172
173";
174		}
175		if ($packed =~ /kit/) {		# Kit parts
176			print MAILER
177"	Subject: Command
178	\@PACK shar
179	\@SH maildist $dest kit -
180
181and you will get the latest release of kit as shell archives.
182
183$mail_help
184
185";
186			# Repeat instructions which should be provided by kit anyway
187			if ($npart > 1) {
188				print MAILER
189"Unkit:	Save this mail into a file, e.g. \"foo$part_num\" and wait until
190	you have received the $npart parts. Then, do \"unkit foo*\". To see
191	what will be extracted, you may wish to do \"unkit -l foo*\" before.
192";
193			} else {
194				print MAILER
195"Unkit:	Save this mail into a file, e.g. \"foo\". Then do \"unkit foo\". To see
196	what will be extracted, you may wish to do \"unkit -l foo\" before.
197";
198			}
199			# If we used the minikit, signal where instruction may be found
200			if ($packed eq 'minikit') {
201				print MAILER
202"	This kit archive also contains a minikit which will enable you to
203	extract the files even if you do not have kit. Please follow the
204	instructions kit has provided for you at the head of each part. Should
205	the minikit prove itself useless, you may wish to get kit.
206";
207			}
208		} else {			# Shar parts
209			print MAILER
210"This is a shar file. It will be simpler to unshar it if you own the Rich Salz's
211cshar package. If you do not have it, send me the following mail:
212
213	Subject: Command
214	\@PACK shar
215	\@SH maildist $dest cshar 3.0
216
217and you will get cshar as shell archives.
218
219$mail_help
220
221";
222			if (-s 'PACKNOTES') {		# Problems detected by maniscan
223				print MAILER
224"
225Warning:
226	Some minor problems were encountered during the building of the
227	shell archives. Perhaps a big file has been split, a binary has been
228	uu-encoded, or some lines were too long. Once you have unpacked the
229	whole distribution, see file PACKNOTES for more information. You can
230	run it through sh by typing 'sh PACKNOTES' to restore possible splited
231	or encoded files.
232
233";
234			}
235			if ($npart > 1) {
236				print MAILER
237"Unshar: Save this mail into a file, e.g. \"foo$part_num\" and wait until
238	you have received the $npart parts. Then, do \"unshar -n foo*\". If you
239	do not own \"unshar\", edit the $npart files and remove the mail header
240	by hand before feeding into sh.
241";
242			} else {
243				print MAILER
244"Unshar: Save this mail into a file, e.g. \"foo\". Then do \"unshar -n foo\". If
245	you do not own \"unshar\", edit the file and remove the mail header by
246	hand before feeding into sh.
247";
248			}
249		}
250		print MAILER
251"
252-- $prog_name speaking for $cf'user
253
254
255";
256		open(PART, $part) || &abort("CANNOT OPEN $part");
257		while (<PART>) {
258			print MAILER;
259		}
260		close PART;
261		close MAILER;
262		if ($?) {
263			&add_log("ERROR couldn't send $size bytes to $dest")
264				if $loglvl > 1;
265		} else {
266			&add_log("SENT $size bytes to $dest") if $loglvl > 2;
267			$partsent++;
268			$bytesent += $size;
269		}
270	}
271
272	# Prepare log message
273	local($partof) = "";
274	local($byteof) = "";
275	local($part);
276	local($byte);
277	if ($partsent > 1) {
278		$part = "parts";
279	} else {
280		$part = "part";
281	}
282	if ($bytesent > 1) {
283		$byte = "bytes";
284	} else {
285		$byte = "byte";
286	}
287	if ($partsent != $npart) {
288		$partof = " (of $npart)";
289		$byteof = "/$nbyte";
290	}
291	&add_log(
292		"SENT $partsent$partof $packed $part ($bytesent$byteof $byte) to $dest"
293	) if $loglvl > 4;
294}
295
296# In case something got wrong
297# We call the clean_tmp routine, which must be defined in the
298# main program that will use abort.
299sub abort {
300	local($reason) = shift;		# Why do we abort ?
301	local($cmd) = $fullcmd =~ /^(\S+)/;
302	open(MAILER, "|$cf'sendmail $cf'mailopt $path $cf'email");
303	print MAILER
304"To: $path
305Subject: $cmd failed
306X-Mailer: mailagent [version $mversion-$revision]
307
308Sorry, the $prog_name command failed while sending files.
309
310Your command was: $fullcmd
311Error message I got:
312
313	>>>> $reason <<<<
314
315If $cf'name can figure out what you meant, he may answer anyway.
316
317-- $prog_name speaking for $cf'user
318";
319	close MAILER;
320	&add_log("FAILED ($reason)") if $loglvl > 1;
321	&clean_tmp;
322	exit 0;			# Scheduled error
323}
324
325