1 /*
2  *	(c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
3  *      Copyright (c) 1996-2005 Michael T Pins.  All rights reserved.
4  *
5  *	Save (or print) articles
6  */
7 
8 #include <unistd.h>
9 #include <signal.h>
10 #include <errno.h>
11 #include <string.h>
12 #include <time.h>
13 #include <stdio.h>
14 #include "config.h"
15 #include "global.h"
16 #include "db.h"
17 #include "decode.h"
18 #include "digest.h"
19 #include "folder.h"
20 #include "more.h"
21 #include "news.h"
22 #include "save.h"
23 #include "nn_term.h"
24 #include "unshar.h"
25 
26 /* save.c */
27 
28 static char    *ckdir_path(char *name);
29 static int      mkdirs_in_path(char *name, char *start);
30 
31 char           *default_save_file = "+$F";
32 char           *folder_save_file = NULL;
33 int             suggest_save_file = 1;
34 char           *unshar_header_file = "Unshar.Headers";
35 int             use_mail_folders = 0;
36 int             use_path_in_from = 0;
37 int             use_mmdf_folders = 0;
38 int             save_report = 1;
39 int             quick_save = 0;
40 int             conf_append = 0;
41 int             conf_create = 1;
42 int             folder_format_check = 1;
43 
44 char           *saved_header_escape = "~";
45 
46 char           *print_header_lines = "FDGS";
47 char           *save_header_lines = "FDNS";
48 static char    *short_header_lines;
49 
50 char           *save_counter_format = "%d";	/* format of save counter */
51 int             save_counter_offset = 0;
52 
53 char            printer[FILENAME] = DEFAULT_PRINTER;
54 int             edit_print_command = 1;
55 
56 char            patch_command[FILENAME] = "patch -p0";
57 int             edit_patch_command = 1;
58 
59 char            unshar_command[FILENAME] = SHELL;
60 int             edit_unshar_command = 0;
61 
62 extern char    *temp_file;
63 extern int      shell_restrictions;
64 extern char     delayed_msg[];
65 
66 extern int      current_folder_type;
67 
68 extern int      rot13_active;
69 
70 extern char    *ctime();
71 
72 static int      save_mode;
73 static char    *unshar_cmd;
74 
75 #define	HEADER_HANDLING	0x0f	/* what should we do with the header */
76 
77 #define	NO_HEADER	0	/* save without a header */
78 #define SHORT_HEADER	1	/* save with partial header */
79 #define	FULL_HEADER	2	/* save with full header */
80 #define	SHORT_HEADER_DG	3	/* save with partial header (digest) */
81 #define	HEADER_ONLY	4	/* save with *only* the header */
82 
83 int             print_header_type = SHORT_HEADER;
84 
85 #define	SEPARATE_FILES	0x0100	/* save as separate files */
86 #define UNIQUE_FILES	0x0200	/* save in unique files */
87 #define	FILE_IS_NEW	0x0400	/* this is a new file */
88 #define APPEND_ARTNUM	0x0800	/* append article number to file name */
89 #define	IS_PIPE		0x1000	/* output is on pipe */
90 #define	DO_UNSHAR	0x2000	/* unshar article (or patch) */
91 #define	DO_PATCH	0x4000	/* patch article */
92 #define	DO_DECODE	0x8000	/* uudecode article */
93 
94 /* open modes for open_news_article for the various HEADER_HANDLINGs */
95 
96 static int      open_mode[] = {
97     SKIP_HEADER,
98     FILL_NEWS_HEADER | SKIP_HEADER | GET_ALL_FIELDS,
99     0,
100     FILL_NEWS_HEADER | FILL_DIGEST_HEADER | SKIP_HEADER | GET_ALL_FIELDS,
101     FILL_NEWS_HEADER
102 };
103 
104 static FILE    *save_file;	/* output stream for saved files */
105 static char    *save_name;	/* save file name */
106 
107 static int      uniq_counter;	/* separate files counter */
108 static char     uniq_format[FILENAME];	/* sprintf format for '*' expansion */
109 
110 static char     last_dir[FILENAME] = "";
111 
112 /*
113  * return pointer to first path name component, that does not exist
114  */
115 
116 static char    *
ckdir_path(char * name)117 ckdir_path(char *name)
118 {
119     char           *slash;
120     char           *component;
121 
122     component = name;
123 
124     while ((slash = strchr(component, '/'))) {
125 	if (slash == component) {
126 	    /* ...//...  */
127 	    component++;
128 	    continue;
129 	}
130 	*slash = NUL;
131 	if (file_exist(name, "drx")) {
132 	    *slash++ = '/';
133 	    component = slash;
134 	    continue;
135 	}
136 	if (file_exist(name, (char *) NULL)) {
137 	    *slash = '/';
138 	    return NULL;
139 	}
140 	*slash = '/';
141 	break;
142     }
143     return component;
144 }
145 
146 /*
147  * create directories in path name, starting from start
148  */
149 
150 static int
mkdirs_in_path(char * name,char * start)151 mkdirs_in_path(char *name, char *start)
152 {
153     char           *slash;
154     char           *component;
155 
156     component = start;
157 
158     while ((slash = strchr(component, '/'))) {
159 	if (slash == component) {
160 	    /* ...//...  */
161 	    component++;
162 	    continue;
163 	}
164 	*slash = NUL;
165 	if (mkdir(name, 0755)) {
166 	    msg("Cannot make %s/", name);
167 	    *slash = '/';
168 	    return 0;
169 	}
170 	*slash++ = '/';
171 	component = slash;
172     }
173     return 1;
174 }
175 
176 static void
set_folder_type(char * name)177 set_folder_type(char *name)
178 {
179     FILE           *f;
180 
181     current_folder_type = -1;
182     if (!folder_format_check)
183 	return;
184 
185     if ((f = open_file(name, OPEN_READ)) != NULL) {
186 	get_folder_type(f);
187 	fclose(f);
188     }
189 }
190 
191 char           *
init_save(int command,char ** mode_textp)192 init_save(int command, char **mode_textp)
193 {
194     char           *mode_text;
195     static char     last_input[FILENAME] = "";
196     static char     name_buf[512];	/* buffer for file name expansion */
197     char           *start, *last, *np;
198 
199     uniq_counter = 0;
200     short_header_lines = save_header_lines;
201 
202     switch (command) {
203 
204 	case K_SAVE_FULL_HEADER:
205 	    save_mode = FULL_HEADER;
206 	    mode_text = "Save";
207 	    goto cont_save;
208 
209 	case K_SAVE_SHORT_HEADER:
210 	    save_mode = SHORT_HEADER;
211 	    mode_text = "Output";
212 	    goto cont_save;
213 
214 	case K_SAVE_HEADER_ONLY:
215 	    save_mode = HEADER_ONLY;
216 	    mode_text = "Header_save";
217 	    goto cont_save;
218 
219 	case K_SAVE_NO_HEADER:
220 	    save_mode = NO_HEADER;
221 	    mode_text = "Write";
222 
223     cont_save:
224 	    if (quick_save && (current_group->group_flag & G_FOLDER) == 0) {
225 		if (current_group->save_file)
226 		    save_name = current_group->save_file;
227 		else
228 		    save_name = default_save_file;
229 		strcpy(last_input, save_name);
230 		save_name = last_input;
231 	    } else {
232 		prompt("\1%s on\1 (+~|) ", mode_text);
233 
234 		save_name = current_group->save_file;
235 		if (save_name == NULL && suggest_save_file)
236 		    save_name = (current_group->group_flag & G_FOLDER) ?
237 			folder_save_file : default_save_file;
238 		if (save_name != NULL) {
239 		    if (!expand_file_name(name_buf, save_name, 2))
240 			return NULL;
241 		    save_name = name_buf;
242 		}
243 		save_name = get_s(last_input, save_name, NONE, file_completion);
244 		if (save_name == NULL || *save_name == NUL)
245 		    return NULL;
246 
247 		if (save_name[1] == NUL && save_name[0] == '+')
248 		    save_name = (current_group->group_flag & G_FOLDER) ?
249 			folder_save_file : default_save_file;
250 		else if (current_group->save_file == NULL ||
251 			 strcmp(save_name, current_group->save_file))
252 		    strcpy(last_input, save_name);
253 		if (save_name == NULL || *save_name == NUL)
254 		    return NULL;
255 	    }
256 
257 	    if (*save_name == '|') {
258 		if (shell_restrictions) {
259 		    msg("Restricted operation - pipes not allowed");
260 		    return NULL;
261 		}
262 		mode_text = "Pipe";
263 		save_name++;
264 		save_mode |= IS_PIPE;
265 		if (*save_name == '|') {
266 		    save_mode |= SEPARATE_FILES;
267 		    save_name++;
268 		}
269 	    }
270 	    if (!expand_file_name(name_buf, save_name, (save_mode & IS_PIPE) ? 11 : 3))
271 		return NULL;
272 	    save_name = name_buf;
273 
274 	    if ((save_mode & IS_PIPE) == 0) {
275 		np = strrchr(save_name, '*');
276 		if (np != NULL) {
277 		    *np = NUL;
278 		    sprintf(uniq_format, "%s%s%s",
279 			    save_name, save_counter_format, np + 1);
280 		    *np = '*';
281 		    save_mode |= SEPARATE_FILES | UNIQUE_FILES;
282 		} else {
283 		    np = strrchr(save_name, '$');
284 		    if (np != NULL && np[1] == 'N') {
285 			if (current_group->group_flag & G_FOLDER) {
286 			    msg("$N is not defined in a folder");
287 			    return NULL;
288 			}
289 			*np = NUL;
290 			sprintf(uniq_format, "%s%%ld%s", save_name, np + 2);
291 			*np = '$';
292 			save_mode |= SEPARATE_FILES | APPEND_ARTNUM;
293 		    }
294 		}
295 	    }
296 	    break;
297 
298 	case K_UUDECODE:
299 	    save_mode = NO_HEADER | DO_UNSHAR | DO_DECODE;
300 	    mode_text = "Decode";
301 	    goto unshar1;
302 
303 	case K_PATCH:
304 	    save_mode = NO_HEADER | SEPARATE_FILES | DO_UNSHAR | DO_PATCH;
305 	    mode_text = "Patch";
306 	    if (!shell_restrictions && edit_patch_command) {
307 		prompt("\1Patch command:\1 ");
308 		save_name = get_s(NONE, patch_command, NONE, NULL_FCT);
309 		if (save_name == NULL || *save_name == NUL)
310 		    return NULL;
311 		strcpy(patch_command, save_name);
312 	    }
313 	    unshar_cmd = patch_command;
314 	    goto unshar1;
315 
316 	case K_UNSHAR:
317 	    save_mode = NO_HEADER | SEPARATE_FILES | DO_UNSHAR;
318 	    mode_text = "Unshar";
319 	    if (!shell_restrictions && edit_unshar_command) {
320 		prompt("\1Unshar command:\1 ");
321 		save_name = get_s(NONE, unshar_command, NONE, NULL_FCT);
322 		if (save_name == NULL || *save_name == NUL)
323 		    return NULL;
324 		strcpy(unshar_command, save_name);
325 	    }
326 	    unshar_cmd = unshar_command;
327 
328     unshar1:
329 	    prompt("\1%s Directory:\1 ", mode_text);
330 	    save_name = current_group->save_file;
331 	    if (save_name != NULL) {
332 		if (!expand_file_name(name_buf, save_name, 10))
333 		    return NULL;
334 		save_name = name_buf;
335 	    }
336 	    save_name = get_s(last_dir, save_name, NONE, file_completion);
337 	    if (save_name == NULL || *save_name == NUL)
338 		return NULL;
339 	    strcpy(last_dir, save_name);
340 	    if (!expand_file_name(name_buf, save_name, 1))
341 		return NULL;
342 	    save_name = name_buf;
343 	    break;
344 
345 	case K_PRINT:
346 	    if (print_header_type < NO_HEADER || print_header_type > FULL_HEADER) {
347 		msg("Invalid 'print-header-type' value %d", print_header_type);
348 		print_header_type = NO_HEADER;
349 	    }
350 	    short_header_lines = print_header_lines;
351 	    save_mode = print_header_type | IS_PIPE;
352 
353 	    if (!shell_restrictions && edit_print_command) {
354 		prompt("\1Print command:\1 ");
355 		save_name = get_s(NONE, printer, NONE, NULL_FCT);
356 		if (save_name == NULL || *save_name == NUL)
357 		    return NULL;
358 		strcpy(printer, save_name);
359 	    }
360 	    if (!expand_file_name(name_buf, printer, 1))
361 		return NULL;
362 	    save_name = name_buf;
363 	    mode_text = "Print";
364 	    break;
365 
366 	default:
367 	    msg("Illegal save command: %d", command);
368 	    return NULL;
369     }
370 
371     if (save_name == NULL)
372 	return NULL;
373 
374     if (!(save_mode & IS_PIPE)) {
375 	if (file_exist(save_name, (save_mode & DO_UNSHAR) ? "wd" : "wf")) {
376 	    if (save_mode & DO_UNSHAR) {
377 		int             len = strlen(save_name);
378 		if (save_name[len - 1] != '/')
379 		    strcpy(save_name + len, "/");
380 	    } else if (conf_append) {
381 		tprintf("\rAppend to: %s ? ", save_name);
382 		clrline();
383 		if (!yes(0))
384 		    return NULL;
385 	    }
386 	} else {
387 	    if (errno != ENOENT) {
388 		msg("Cannot access %s", save_name);
389 		return NULL;
390 	    }
391 	    if (save_mode & DO_UNSHAR) {
392 		int             len = strlen(save_name);
393 		if (save_name[len - 1] != '/')
394 		    strcpy(save_name + len, "/");
395 	    }
396 	    start = ckdir_path(save_name);
397 	    if (start == NULL) {
398 		msg("No permission");
399 		return NULL;
400 	    }
401 	    last = strrchr(start, '/');
402 	    /* last != NULL => non-existing directories */
403 
404 	    if (conf_create && (!(save_mode & SEPARATE_FILES) || last)) {
405 		tprintf("\rCreate ");
406 		for (np = save_name; *np; np++) {
407 		    if (np == start)
408 			tputc('\"');
409 		    tputc(*np);
410 		    if ((save_mode & SEPARATE_FILES) && np == last)
411 			break;
412 		}
413 		tprintf("\" ?");
414 		clrline();
415 		if (yes(last != NULL) <= 0)
416 		    return NULL;
417 	    }
418 	    if (last && !mkdirs_in_path(save_name, start))
419 		return NULL;
420 	}
421     }
422     if (mode_textp)
423 	*mode_textp = mode_text;
424 
425     save_mode |= FILE_IS_NEW;	/* so save() will open it */
426 
427     if (save_mode & DO_DECODE) {
428 	uud_start(save_name);
429 	save_mode &= ~DO_UNSHAR;
430     }
431     return save_name;
432 }
433 
434 
435 int
save(article_header * ah)436 save(article_header * ah)
437 {
438     register FILE  *art;
439     register int    c, lcount = 0, mode;
440     news_header_buffer hdrbuf;
441     news_header_buffer dghdrbuf;
442     int             was_raw = 0, set_visual = 0;
443     char            copybuf[FILENAME * 4], uniqbuf[FILENAME];
444     flag_type       nn_st_flag = A_ST_FILED;
445     int             with_header;
446 
447     if (ah->a_group)
448 	init_group(ah->a_group);
449 
450     mode = save_mode & HEADER_HANDLING;
451     if (mode == SHORT_HEADER && ah->flag & A_DIGEST)
452 	mode = SHORT_HEADER_DG;
453 
454     c = open_mode[mode];
455     if (use_mail_folders && use_path_in_from && (c & FILL_NEWS_HEADER) == 0)
456 	c |= FILL_NEWS_HEADER | GET_ALL_FIELDS;
457 
458     art = open_news_article(ah, c, hdrbuf, dghdrbuf);
459     if (art == NULL) {
460 	msg("Cannot read %s", group_path_name);
461 	return 0;
462     }
463     if (save_mode & DO_DECODE) {
464 	save_file = NULL;
465 	c = uudecode(ah, art);
466 	fclose(art);
467 	return (c < 0) ? 0 : 1;
468     }
469     if (save_mode & UNIQUE_FILES) {
470 	uniqbuf[0] = NUL;
471 	do {
472 	    strcpy(copybuf, uniqbuf);
473 	    uniq_counter++;
474 	    sprintf(uniqbuf, uniq_format, uniq_counter + save_counter_offset);
475 	    if (strcmp(uniqbuf, copybuf) == 0) {
476 		msg("save-counter \"%s\" does not generate unique file names",
477 		    save_counter_format);
478 		goto fatal;
479 	    }
480 	} while (file_exist(uniqbuf, (char *) NULL));
481 	save_name = uniqbuf;
482 	save_mode |= FILE_IS_NEW;
483     } else if (save_mode & APPEND_ARTNUM) {
484 	sprintf(uniqbuf, uniq_format, (long) (ah->a_number));
485 	save_name = uniqbuf;
486     }
487     if (save_mode & FILE_IS_NEW) {
488 	if (save_mode & (IS_PIPE | DO_UNSHAR)) {
489 	    set_visual = 1;
490 	    was_raw = visual_off();
491 	}
492 	if (save_mode & IS_PIPE) {
493 	    if ((save_file = popen(save_name, "w")) == NULL) {
494 		msg("Cannot pipe to %s", save_name);
495 		goto fatal;
496 	    }
497 	} else if (save_mode & DO_UNSHAR) {
498 	    if ((save_mode & DO_PATCH) == 0) {
499 		if (!unshar_position(art))
500 		    goto fatal;
501 		if (unshar_header_file)
502 		    store_header(ah, art, save_name, unshar_header_file);
503 	    }
504 	    new_temp_file();
505 	    sprintf(copybuf,
506 	    "cd %s && { %s 2>&1 ; } | tee %s ; cat %s >> %s.Result ; rm %s",
507 		    save_name != NULL ? save_name : ".", unshar_cmd,
508 		    temp_file, temp_file,
509 		    (save_mode & DO_PATCH) ? "Patch" : "Unshar",
510 		    temp_file);
511 
512 	    save_file = popen(copybuf, "w");
513 	    if (save_file == NULL) {
514 		msg("Cannot exec: '%s'", copybuf);
515 		goto fatal;
516 	    }
517 	    tprintf("\r\n%s %s\r\n",
518 		    save_mode & DO_PATCH ? "PATCHING FROM" : "UNPACKING",
519 		    ah->subject ? ah->subject : "ARTICLE");
520 	    fl;
521 	} else {
522 	    if ((save_file = open_file(save_name, OPEN_APPEND)) == NULL) {
523 		msg("Cannot write %s", save_name);
524 		fclose(art);
525 		return 0;
526 	    }
527 	    current_folder_type = -1;
528 	    if (ftell(save_file) != (off_t) 0) {
529 		if (mode != NO_HEADER)
530 		    set_folder_type(save_name);
531 		save_mode &= ~FILE_IS_NEW;
532 	    }
533 	}
534     }
535     clrline();
536     s_pipe = 0;
537 
538     with_header = mode != NO_HEADER &&
539 	(save_mode & (IS_PIPE | DO_UNSHAR)) == 0;
540 
541     if (with_header)
542 	mailbox_format(save_file, 1);
543 
544     if (mode == FULL_HEADER || mode == HEADER_ONLY) {
545 	off_t           cnt = ah->fpos - ah->hpos;
546 	while (--cnt >= 0) {
547 	    if ((c = getc(art)) == EOF)
548 		break;
549 	    putc(c, save_file);
550 	}
551     } else if (mode == SHORT_HEADER || mode == SHORT_HEADER_DG) {
552 	char           *name, *val;
553 	scan_header_fields(short_header_lines, ah);
554 	while (next_header_field(&name, &val, (fct_type *) NULL)) {
555 	    if (name == NULL)
556 		continue;
557 	    fprintf(save_file, "%s: %s\n", name, val);
558 	}
559 	fputc(NL, save_file);
560     }
561     fflush(save_file);
562     if (s_pipe)
563 	goto broken_pipe;
564 
565     if (mode != HEADER_ONLY) {
566 	lcount = 0;
567 	while (ftell(art) < ah->lpos && fgets(copybuf, 512, art)) {
568 	    lcount++;
569 	    if (rot13_active)
570 		rot13_line(copybuf);
571 	    if (saved_header_escape && with_header && is_header_line(copybuf))
572 		fputs(saved_header_escape, save_file);
573 	    fputs(copybuf, save_file);
574 	    if (s_pipe)
575 		goto broken_pipe;
576 	}
577     }
578     if (with_header)
579 	lcount += mailbox_format(save_file, 0);
580 
581 broken_pipe:
582     fclose(art);
583 
584     if (save_mode & DO_UNSHAR) {
585 	if ((c = pclose(save_file)) != 0) {
586 	    sprintf(delayed_msg, "Save command failed; exit = %d", c);
587 	    nn_st_flag = 0;
588 	}
589 	save_file = NULL;
590     } else {
591 	if (s_pipe)
592 	    msg("Command did not read complete article!");
593 	else if (save_report)
594 	    msg((save_mode & IS_PIPE) ? "%s: %d lines piped" :
595 		(save_mode & FILE_IS_NEW) ? "%s created: %d lines written" :
596 		"%s: %d lines appended", save_name, lcount);
597 
598 	if (s_pipe || (save_mode & SEPARATE_FILES)) {
599 	    if (end_save() == 0)
600 		goto err;
601 	} else
602 	    save_mode &= ~FILE_IS_NEW;
603     }
604 
605 #ifdef MAIL_READING
606     if (mail_auto_delete && (save_mode & IS_PIPE) == 0)
607 	if (current_group->group_flag & G_MAILBOX)
608 	    if (ah->attr != A_CANCEL)
609 		fcancel(ah);
610 #endif
611 
612     if (set_visual)
613 	visual_on();
614     if (was_raw)
615 	nn_raw();
616 
617     ah->flag |= nn_st_flag;
618 
619     return !s_pipe || (save_mode & SEPARATE_FILES);
620 
621 fatal:
622     fclose(art);
623 err:
624     if (set_visual)
625 	visual_on();
626     if (was_raw)
627 	nn_raw();
628     return 0;
629 }
630 
631 int
end_save(void)632 end_save(void)
633 {
634     int             c;
635     FILE           *sf;
636     sf = save_file;
637     save_file = NULL;
638 
639     if (sf) {
640 	if (save_mode & (IS_PIPE | DO_UNSHAR)) {
641 	    if ((c = pclose(sf)) != 0) {
642 		if (c >= 256)
643 		    c >>= 8;	/* HACK */
644 		sprintf(delayed_msg, "Save command failed; exit = %d", c);
645 		return 0;
646 	    }
647 	} else if (fclose(sf) == EOF) {
648 	    sprintf(delayed_msg, "Save failed (disk full?)");
649 	    return 0;
650 	}
651     }
652     if (save_mode & DO_DECODE) {
653 	uud_end();
654     }
655     if (save_mode & DO_UNSHAR)
656 	sprintf(delayed_msg, "Output is saved in %s/%s.Result",
657 		save_name != NULL ? save_name : ".",
658 		(save_mode & DO_PATCH) ? "Patch" : "Unshar");
659     return 1;
660 }
661 
662 void
store_header(article_header * ah,FILE * f,char * dir,char * file)663 store_header(article_header * ah, FILE * f, char *dir, char *file)
664 {
665     register int    c;
666     off_t           endpos;
667     FILE           *h;
668 
669     if (dir != (char *) NULL && file[0] != '/')
670 	file = relative(dir, file);
671     if ((h = open_file(file, OPEN_APPEND)) == NULL) {
672 	msg("Cannot open %s", file);
673 	return;
674     }
675     fseek(h, 0, 2);
676     if (ftell(h) > 0)
677 	set_folder_type(file);
678     else
679 	current_folder_type = -1;
680     if (!use_mmdf_folders && ftell(h) > 0)
681 	putc(NL, h);		/* just in case */
682     mailbox_format(h, 1);
683     endpos = ftell(f) - ah->hpos;
684     fseek(f, ah->hpos, 0);
685     while (--endpos >= 0 && (c = getc(f)) != EOF)
686 	putc(c, h);
687 
688     mailbox_format(h, 0);
689     fclose(h);
690 }
691 
692 int
mailbox_format(FILE * f,int top)693 mailbox_format(FILE * f, int top)
694 {
695     time_t          now;
696     int             do_mmdf, do_mail;
697 
698     do_mmdf = do_mail = 0;
699     switch (current_folder_type) {
700 	case 0:
701 	    break;
702 	case 1:
703 	    do_mail = 1;
704 	    break;
705 	case 2:
706 	    do_mmdf = 1;
707 	    break;
708 	default:
709 	    do_mmdf = use_mmdf_folders;
710 	    do_mail = use_mail_folders;
711 	    break;
712     }
713 
714     if (do_mmdf) {
715 	fprintf(f, "\001\001\001\001\n");
716 	return 0;
717     }
718     if (top == 0) {
719 	fputc(NL, f);
720 	return 1;
721     }
722     if (top > 0 && do_mail) {
723 	now = cur_time();
724 	fprintf(f, "From %s %s",
725 		(use_path_in_from && news.ng_path) ? news.ng_path :
726 		current_group->group_name, ctime(&now));
727 	return 1;
728     }
729     return 0;
730 }
731 
732 char           *
run_mkdir(char * dir,char * name_buf)733 run_mkdir(char *dir, char *name_buf)
734 {
735     if (dir == NULL) {
736 	prompt("\1Directory: \1");
737 	dir = get_s(last_dir, NONE, NONE, file_completion);
738 	if (dir == NULL || *dir == NUL)
739 	    return NULL;
740 	strcpy(last_dir, dir);
741     }
742     if (*dir == '+' || *dir == '~') {
743 	if (!expand_file_name(name_buf, dir, 1))
744 	    return NULL;
745 	dir = name_buf;
746     }
747     if (file_exist(dir, (char *) NULL)) {
748 	msg("Directory %s already exists", dir);
749 	return NULL;
750     }
751     if (mkdir(dir, 0755)) {
752 	msg("Cannot make %s", dir);
753 	return NULL;
754     }
755     return dir;
756 }
757 
758 int
change_dir(char * dir,int in_init)759 change_dir(char *dir, int in_init)
760 {
761     char            dir_buf[FILENAME];
762 
763     if (dir == NULL) {
764 	prompt("\1Directory: \1");
765 	dir = get_s(last_dir, NONE, NONE, file_completion);
766     }
767     if (dir == NULL || *dir == NUL)
768 	return 0;
769 
770     strcpy(last_dir, dir);
771 
772     if (*dir == '+' || *dir == '~') {
773 	if (!expand_file_name(dir_buf, dir, 1))
774 	    return in_init;
775 	dir = dir_buf;
776     }
777     if (chdir(dir) == 0) {
778 	if (!in_init)
779 	    msg("Directory: %s", dir);
780 	return 0;
781     }
782     if (in_init)
783 	return 1;
784 
785     if (errno == EACCES)
786 	msg("Cannot access directory %s", dir);
787     else {
788 	/* should ask and create directory here */
789 	msg("Directory not found: %s", dir);
790     }
791 
792     return 0;
793 }
794