#include "ftptool.h"

#pragma ident   "@(#)view_file.c 1.7     93/06/24"

#ifdef USE_PROTOTYPES
int start_viewer(char *filename, int isremote)
#else
int start_viewer(filename, isremote)
char	*filename;
int		isremote;
#endif
{
	struct extension_info *ext_info;
	char	*viewer = default_viewer;
	char	*ext = "default";
	int	type;
	char	**argv;


	ext_info = type_by_either(filename);
	if (ext_info != NULL) {
		/* magic number matched */
		viewer = ext_info->program;
		ext = ext_info->extension;
		type = ext_info->type;
	} else {
		/* both NULL, try default */
		viewer = default_viewer;
		ext = "default";
		type = FILE_VIEWER;
	}

	if (type == FILE_DECOMPRESSOR) {
		/* uncompress file */
		if (isremote)
			footer_message("Uncompressing %s.", filename);
		else
			local_footer_message("Uncompressing %s.", filename);
		argv = build_argv(viewer, filename);
		pipe_program(argv);
		free_argv(argv);
		return (COMPRESSED);
	}


	if (isremote) {
		footer_message("Starting %s viewer %s.", ext, viewer);
	} else {
		local_footer_message("Starting %s viewer %s.", ext, viewer);
	}
	fork_viewer(viewer, filename);
	return (0);
}

#ifdef USE_PROTOTYPES
char **build_argv(char *program, char *filename)
#else
char **build_argv(program, filename)
char *program, *filename;
#endif
{
	int	argc;
	char	*arg;
	char	**argv;
	int	percentf = 0;
	char	*p;

	/* count number of words */
	argc = 0;
	p = strdup(program);
	if (p == NULL) {
		fprintf(stderr, "Out of memory.\n");
		exit(1);
	}
	arg = p;
	while (*arg && isspace(*arg))
		arg++;
	while (*arg) {
		/* found an arg */
		argc++;
		/* skip arg */
		while (*arg && !isspace(*arg))
			arg++;
		/* skip WS */
		while (*arg && isspace(*arg))
			arg++;
	}
	if (argc == 0) {
		fprintf(stderr, "Null viewer.\n");
		exit(1);
	}
	/* allocate argv[]  (extra entry in case no %f specified) */
	argv = (char **)malloc((argc+2) * sizeof (char *));
	if (argv == NULL) {
		fprintf(stderr, "No memory. Cannot start viewer '%s'.\n",
			program);
		exit(1);
	}
	argc = 0;
	arg = strtok(p, " \t\n");
	while (arg) {
		if (!strcmp(arg, "%f")) {
			percentf++;
			argv[argc] = strdup(filename);
			if (argv[argc] == NULL) {
				fprintf(stderr, "Out of memory.\n");
				exit(1);
			}
		} else {
			argv[argc] = strdup(arg);
			if (argv[argc] == NULL) {
				fprintf(stderr, "Out of memory.\n");
				exit(1);
			}
		}
		argc++;
		arg = strtok((char *)NULL, " \t\n");
	}
	/* %f means file name */
	if (!percentf) {
		argv[argc] = strdup(filename);
		if (argv[argc] == NULL) {
			fprintf(stderr, "Out of memory.\n");
			exit(1);
		}
		argc++;
	}
	argv[argc] = NULL;
	free(p);
	return (argv);
}

#ifdef USE_PROTOTYPES
void free_argv(char **argv)
#else
void free_argv(argv)
char	**argv;
#endif
{
	char **tmp;

	tmp = argv;
	while (*tmp) {
		free(*tmp);
		tmp++;
	}
	free(argv);
}

#ifdef USE_PROTOTYPES
void fork_viewer(char *program, char *filename)
#else
void fork_viewer(program, filename)
char	*program;
char	*filename;
#endif
{
	int	pid;
	char	**argv;

	switch (pid = fork()) {
	case -1:
		perror("fork");
		break;
	case 0: /* child */
		argv = build_argv(program, filename);
		execvp(argv[0], argv);
		fprintf(stderr, "viewer '%s' failed:", program);
		perror("");
		exit(1);
	default: /* parent */
		notify_set_wait3_func(base_window.frame, notify_default_wait3,
		    pid);
		break;
	}
}

#ifdef USE_PROTOTYPES
int iscompressed(char *filename)
#else
int iscompressed(filename)
char	*filename;
#endif
{
	struct extension_info *ext_info;

	ext_info = type_by_either(filename);
	if (ext_info != NULL) {
		if (ext_info->type == FILE_DECOMPRESSOR) {
			return (1);
		} else {
			return (0);
		}
	} else {
		return (0);
	}
}

#ifdef USE_PROTOTYPES
void pipe_program(char *argv[])
#else
void pipe_program(argv)
char	*argv[];
#endif
{
	int	pid;
	int pipe_fds[2];
	char scratch[100];
	FILE	*fp;

	if (pipe(pipe_fds) == -1) {
		perror("ftptool:pipe");
		return;
	}

	switch (pid = fork()) {
	case -1:
		perror("fork");
		break;
	case 0: /* child */
		dup2(pipe_fds[1], 1);
		dup2(pipe_fds[1], 2);
		close(pipe_fds[0]);
		close(pipe_fds[1]);
		execvp(argv[0], argv);
		perror("can not start program");
		exit(1);
	default: /* parent */
		notify_set_wait3_func(base_window.frame, notify_default_wait3,
		    pid);
		close(pipe_fds[1]);
		break;
	}
	fp = fdopen(pipe_fds[0], "r");
	if (fp == NULL) {
		perror("fopen");
		close(pipe_fds[0]);
		return;
	}
	notify_do_dispatch();
	while (fgets(scratch, sizeof (scratch), fp) != NULL) {
		notify_no_dispatch();
		log_message(scratch);
		notify_do_dispatch();
	}
	notify_no_dispatch();
	fclose(fp);
}

#ifdef USE_PROTOTYPES
int view_local_file(char *name, int which, int *dirchanged)
#else
int view_local_file(name, which, dirchanged)
char	*name;
int		which;
int		*dirchanged;
#endif
{
	char *dot;
	struct stat buf;

	if (stat(name, &buf) == -1) {
		local_footer_message("%s: %s.", name, sys_errlist[errno]);
		return (1);
	}
	if (!S_ISREG(buf.st_mode)) {
		local_footer_message("%s is not a regular file.", name);
		return (1);
	}
	if (start_viewer(name, which == DOREMOTEVIEW) == COMPRESSED) {
		dot = rindex(name, '.');
		if (dot) {
			*dot = '\0';
			if (which == DOLOCALVIEW && dirchanged != NULL)
				*dirchanged = 1;
			start_viewer(name, which == DOREMOTEVIEW);
		}
	}
	return (0);
}

char *newname;

#ifdef USE_PROTOTYPES
int view_remote_file(char *name, size_t size)
#else
int view_remote_file(name, size)
char	*name;
size_t	size;
#endif
{
	static char *tmpname;
	char scratch[MAXPATHLEN+1];

	if (tmpname == NULL || (access(tmpname, F_OK) == -1 &&
	    errno == ENOENT)) {
		tmpname = tempnam("/var/tmp", "ftptl");
		if (tmpname == NULL || (mkdir(tmpname, 0777) == -1)) {
			footer_message("Can't create temporary directory.");
			return (1);
		}
	}
	sprintf(scratch, "%s/%s", tmpname, name);
	/* newname will be set if a unique local name is generated */
	newname = NULL;
	if (get_file(name, scratch, size)) {
		return (1);
	}

	if (newname)
		strcpy(scratch, newname);

	return (view_local_file(scratch, DOREMOTEVIEW, (int *)NULL));
}

#ifdef USE_PROTOTYPES
struct extension_info *new_extension(char *extension, char *magic,
	char *program, int type)
#else
struct extension_info *new_extension(extension, magic, program, type)
char	*extension;
char 	*magic;
char	*program;
int	type;
#endif
{
	struct extension_info *tmp;

	tmp = (struct extension_info *)malloc(sizeof (*tmp));
	if (tmp == NULL)
		return (NULL);

	tmp->next = NULL;
	tmp->extension = NULL;
	tmp->magic = NULL;
	tmp->program = NULL;

	tmp->extension = strdup(extension);
	if (tmp->extension == NULL)
		goto out;

	tmp->magic = strdup(magic);
	if (tmp->magic == NULL)
		goto out;

	tmp->program = strdup(program);
	if (tmp->program == NULL)
		goto out;

	tmp->type = type;
	return (tmp);
out:
	free_extension(tmp);
	return (NULL);
}

#ifdef USE_PROTOTYPES
void free_extension(struct extension_info *cell)
#else
void free_extension(cell)
struct extension_info *cell;
#endif
{
	if (cell->extension)
		free(cell->extension);
	if (cell->magic)
		free(cell->magic);
	if (cell->program)
		free(cell->program);
	free(cell);
}

#ifdef USE_PROTOTYPES
struct extension_info *add_extension(struct extension_info *head,
	char *extension, char *magic, char *program, int type)
#else
struct extension_info *add_extension(head, extension, magic, program, type)
struct extension_info *head;
char	*extension;
char 	*magic;
char	*program;
int	type;
#endif
{
	struct extension_info *new;
	struct extension_info *tmp;
	int		rval;

	new = new_extension(extension, magic, program, type);
	if (new == NULL) {
		fprintf(stderr, "%s: no memory for new extension.\n",
			program_name);
		return (NULL);
	}

	/* put in alphabetical order */
	for (tmp = head; tmp->next != NULL; tmp = tmp->next) {
		if (ignore_case)
			rval = strcasecmp(extension, tmp->next->extension);
		else
			rval = strcmp(extension, tmp->next->extension);
		if (rval < 0)
			break;
	}

	new->next = tmp->next;
	tmp->next = new;
	return (head);
}

#ifdef USE_PROTOTYPES
int read_extensions(FILE *fp, char *extension, char *magic,
	char *program, int *type)
#else
int read_extensions(fp, extension, magic, program, type)
FILE	*fp;
char	*extension;
char	*magic;
char	*program;
int	*type;
#endif
{
	static char linebuf[2 * MAXPATHLEN + 1];
	static char typebuf[MAXPATHLEN + 1];

	/*
	 * Extension:
	 * Magic:
	 * Program:
	 * Type:
	 * --
	 */
	if (fgets(linebuf, sizeof (linebuf), fp) == NULL) {
		if (feof(fp))
			return (0);
		else
			goto out;
	}
	*extension = '\0';
	sscanf(linebuf, "Extension:%[^\n]", extension);

	if (fgets(linebuf, sizeof (linebuf), fp) == NULL)
		goto out;
	*magic = '\0';
	sscanf(linebuf, "Magic:%[^\n]", magic);

	if (fgets(linebuf, sizeof (linebuf), fp) == NULL)
		goto out;
	*program = '\0';
	sscanf(linebuf, "Program:%[^\n]", program);

	if (fgets(linebuf, sizeof (linebuf), fp) == NULL)
		goto out;

	/* Possible Type field */
	if (!strncmp(linebuf, "Type:", 5)) {
		sscanf(linebuf, "Type:%[^\n]", typebuf);
		if (!strcmp(typebuf, "decompressor"))
			*type = FILE_DECOMPRESSOR;
		else {
			/* file viewer */
			*type = FILE_VIEWER;
		}
		/* Dump separator */
		if (fgets(linebuf, sizeof (linebuf), fp) == NULL)
			goto out;
	}
	/* Dump separator */

	return (1);

out:
	fprintf(stderr, "%s: Bad entry for extension in %s.\n",
		program_name, FTPTOOL_TYPES);
	return (0);
}

#ifdef USE_PROTOTYPES
void load_extensions(void)
#else
void load_extensions()
#endif
{
	char	*ftptool_extensions;
	char	*archive_viewer;
	char	*postscript_viewer;
	FILE	*fp;
	static char extension[MAXPATHLEN + 1];
	static char magic[MAXPATHLEN + 1];
	static char program[MAXPATHLEN + 1];
	int	type;

	extension_list = new_extension("", "", "", FILE_VIEWER);
	if (extension_list == NULL) {
		fprintf(stderr, "%s: Out of memory for extension list.\n",
			program_name);
		return;
	}

	ftptool_extensions = find_dotfile(FTPTOOL_TYPES);
	if (ftptool_extensions == NULL) {
		/* not there, use resources/create initial one */

		archive_viewer = defaults_get_string(
		    "ftptool.ArchiveViewer", "Ftptool.ArchiveViewer",
		    program_name);
		add_extension(extension_list, ".tar", "", archive_viewer,
		    FILE_VIEWER);

		postscript_viewer = defaults_get_string(
		    "ftptool.PostScriptViewer", "Ftptool.PostScriptViewer",
		    "pageview %f");
		add_extension(extension_list, ".ps", "%!", postscript_viewer,
		    FILE_VIEWER);

		/* other stuff */

		add_extension(extension_list, ".gif", "GIF", "xv %f",
		    FILE_VIEWER);

		add_extension(extension_list, ".jpg",
		    "\\377\\330\\377\\340\\000\\020\\112\\106\\111",
		    "xv %f", FILE_VIEWER);

		add_extension(extension_list, ".ras", "\\131\\246\\152\\225",
		    "xv %f", FILE_VIEWER);

		add_extension(extension_list, ".Z", "\\037\\235",
		    "compress -dvf %f", FILE_DECOMPRESSOR);

		add_extension(extension_list, ".z", "", "gzip -dvf %f",
		    FILE_DECOMPRESSOR);

		add_extension(extension_list, ".gz", "", "gzip -dvf %f",
		    FILE_DECOMPRESSOR);

		extensions_changed = 1;

	} else {
		/* load list */
		fp = fopen(ftptool_extensions, "r");
		if (fp == NULL) {
			fprintf(stderr,
			    "%s: Could not open %s for reading (%s).\n",
			    program_name, ftptool_extensions,
			    sys_errlist[errno]);
			free(ftptool_extensions);
			return;
		}
		type = -1;
		while (read_extensions(fp, extension, magic, program, &type)) {
			if (add_extension(extension_list, extension, magic,
			    program, type)
				== NULL)
				break;
		}
		fclose(fp);
		free(ftptool_extensions);
		if (type == -1) {
			/* no compressors */
			add_extension(extension_list,
				".Z", "\\037\\235", "compress -dvf %f",
			    FILE_DECOMPRESSOR);
			add_extension(extension_list,
				".z", "", "gzip -dvf %f", FILE_DECOMPRESSOR);
			add_extension(extension_list,
				".gz", "", "gzip -dvf %f", FILE_DECOMPRESSOR);
			extensions_changed = 1;
		}
	}

	clear_extension_list(tool_property_window.viewers.list);
	load_extension_list(extension_list, tool_property_window.viewers.list);
}

#ifdef USE_PROTOTYPES
void save_extensions(void)
#else
void save_extensions()
#endif
{
	char	*filename = NULL;
	struct extension_info *tmp;
	FILE	*fp;
#ifndef __FreeBSD__
	extern char *sys_errlist[];
#endif
	char	*typename;

	/* create will also truncate, which we want to do here */
	filename = create_dotfile(FTPTOOL_TYPES, 0644);
	if (filename == NULL) {
		fprintf(stderr, "%s: Could not create ftptooltypes file.\n",
			program_name);
		return;
	}

	fp = fopen(filename, "w");
	if (fp == NULL) {
		fprintf(stderr, "%s: Could not open %s for writing (%s).\n",
			program_name, filename, sys_errlist[errno]);
		free(filename);
		return;
	}
	for (tmp = extension_list->next; tmp != NULL; tmp = tmp->next) {
		fprintf(fp, "Extension:%s\n", tmp->extension);
		fprintf(fp, "Magic:%s\n", tmp->magic);
		fprintf(fp, "Program:%s\n", tmp->program);
		switch (tmp->type) {
		case FILE_DECOMPRESSOR:
			typename = "decompressor";
			break;
		case FILE_VIEWER:
		default:
			typename = "file viewer";
			break;
		}
		fprintf(fp, "Type:%s\n", typename);
		fprintf(fp, "--\n");
	}
	fclose(fp);

	extensions_changed = 0;

	free(filename);
}

#ifdef USE_PROTOTYPES
void load_extension_list(struct extension_info *extension_list,
	Panel panel_list)
#else
void load_extension_list(extension_list, panel_list)
struct extension_info *extension_list;
Panel	panel_list;
#endif
{
	struct extension_info *tmp;
	int		row;

	row = 0;
	for (tmp = extension_list->next; tmp != NULL; tmp = tmp->next, row++) {
		xv_set(panel_list,
			PANEL_LIST_INSERT, row,
			PANEL_LIST_STRING, row, tmp->extension,
			PANEL_LIST_CLIENT_DATA, row, tmp,
			PANEL_PAINT, PANEL_NONE,
			NULL);
	}
	xv_set(panel_list,
		XV_SHOW, TRUE,
		NULL);
}

#ifdef USE_PROTOTYPES
void clear_extension_list(Panel panel_list)
#else
void clear_extension_list(panel_list)
Panel panel_list;
#endif
{
	int	nitems;
	int	row;

	nitems = xv_get(panel_list, PANEL_LIST_NROWS);

	for (row = nitems - 1; row >= 0; row--) {
		xv_set(panel_list,
			PANEL_LIST_DELETE, row,
			PANEL_PAINT, PANEL_NONE,
			NULL);
	}
	panel_paint(panel_list, PANEL_CLEAR);
}

#ifdef USE_PROTOTYPES
int extension_list_proc(Panel_item item, char *string, Xv_opaque client_data,
	Panel_list_op op, Event *event)
#else
int extension_list_proc(item, string, client_data, op, event)
Panel_item	item;
char		*string;
Xv_opaque	client_data;
Panel_list_op	op;
Event		*event;
#endif
{
	struct extension_info *tmp = (struct extension_info *)client_data;

	switch (op) {
	case PANEL_LIST_OP_SELECT:
		xv_set(tool_property_window.viewers.extension,
			PANEL_VALUE, tmp->extension,
			NULL);
		caret_to_first(tool_property_window.viewers.extension);
		xv_set(tool_property_window.viewers.magic,
			PANEL_VALUE, tmp->magic,
			NULL);
		caret_to_first(tool_property_window.viewers.magic);
		xv_set(tool_property_window.viewers.program,
			PANEL_VALUE, tmp->program,
			NULL);
		caret_to_first(tool_property_window.viewers.program);
		xv_set(tool_property_window.viewers.type,
			PANEL_VALUE, tmp->type,
			NULL);
		return (XV_OK);
	default:
		return (XV_OK);
	}
}

#ifdef USE_PROTOTYPES
struct extension_info *type_by_extension(char *filename)
#else
struct extension_info *type_by_extension(filename)
char	*filename;
#endif
{
	struct extension_info *tmp;
	unsigned int	len;
	char	*ext;

	for (tmp = extension_list->next; tmp != NULL; tmp = tmp->next) {
		len = strlen(tmp->extension);
		if (strlen(filename) < len)
			continue;
		ext = filename + (strlen(filename) - len);
		if (!strcmp(ext, tmp->extension))
			break;
	}
	return (tmp);

}

#ifdef USE_PROTOTYPES
struct extension_info *type_by_magic(char *filename)
#else
struct extension_info *type_by_magic(filename)
char	*filename;
#endif
{
	struct extension_info *tmp;
	int		fd;
	char	buf[MAX_MAGIC_SIZE];
	char	*chp;
	char	ch;
	int		nread;
	int		count;

	if ((fd = open(filename, O_RDONLY)) == -1) {
		return (NULL);
	}
	notify_do_dispatch();
	nread = read(fd, buf, sizeof (buf));
	notify_no_dispatch();
	close(fd);
	if (nread == -1) {
		return (NULL);
	}

	for (tmp = extension_list->next; tmp != NULL; tmp = tmp->next) {
		count = 0;
		chp = tmp->magic;
		ch = *chp;
		if (ch == '\0') /* null magic number */
			continue;
		/* test and advance */
		while (count < nread && ch != '\0') {
			if (ch == '\\') {
				int	n = 3;
				int	val = 0;

				/* octal escape sequence */
				chp++;
				while (isdigit(*chp) && n > 0) {
					val *= 8;
					val += *chp - '0';
					chp++;
					n--;
				}
				/* point back one for later */
				chp--;
				ch = (char)val;
			}
			if (buf[count] == ch) {
				/* match */
				count++;
				chp++;
				ch = *chp;
			} else
				break;
		}
		if (ch == '\0') {
			break;
		}
	}
	return (tmp);
}

#ifdef USE_PROTOTYPES
struct extension_info *type_by_either(char *filename)
#else
struct extension_info *type_by_either(filename)
char	*filename;
#endif
{
	struct extension_info *type_ext;
	struct extension_info *type_magic;


	type_ext = type_by_extension(filename);
	type_magic = type_by_magic(filename);
	if (type_ext != NULL && type_magic == NULL) {
		/* extension matched, go for it */
		return (type_ext);
	} else if (type_ext == NULL && type_magic != NULL) {
		/* magic number matched */
		return (type_magic);
	} else if (type_ext == NULL && type_ext == type_magic) {
		/* both NULL */
		return (NULL);
	} else if (type_ext == type_magic) {
		/* they match, great! */
		return (type_ext);
	} else {
		/* they both aren't null, and don't match! */
		/* choose magic number, it's probably more correct */
		return (type_magic);
	}
}


#ifdef USE_PROTOTYPES
void delete_extension_proc(Panel_item item, Event *event)
#else
void delete_extension_proc(item, event)
Panel_item	item;
Event 		*event;
#endif
{
	char	*extension;

	xv_set(tool_property_window.frame,
		FRAME_LEFT_FOOTER, "",
		NULL);

	extension = (char *)xv_get(tool_property_window.viewers.extension,
		PANEL_VALUE);
	if (*extension == '\0') {
		xv_set(tool_property_window.frame,
			FRAME_SHOW_FOOTER, TRUE,
			FRAME_LEFT_FOOTER, "Please specify an extension.",
			NULL);
		return;
	}

	delete_extension(extension_list, extension);

	clear_extension_list(tool_property_window.viewers.list);
	load_extension_list(extension_list, tool_property_window.viewers.list);

	xv_set(item,
		PANEL_NOTIFY_STATUS, XV_ERROR,
		NULL);
}

#ifdef USE_PROTOTYPES
void add_extension_proc(Panel_item item, Event *event)
#else
void add_extension_proc(item, event)
Panel_item	item;
Event 		*event;
#endif
{
	enter_extension_info(1);
	xv_set(item,
		PANEL_NOTIFY_STATUS, XV_ERROR,
		NULL);
}

#ifdef USE_PROTOTYPES
void change_extension_proc(Panel_item item, Event *event)
#else
void change_extension_proc(item, event)
Panel_item	item;
Event 		*event;
#endif
{
	enter_extension_info(0);
	xv_set(item,
		PANEL_NOTIFY_STATUS, XV_ERROR,
		NULL);
}

#ifdef USE_PROTOTYPES
void enter_extension_info(int warnchange)
#else
void enter_extension_info(warnchange)
int	warnchange;
#endif
{
	int	answer;
	char *extension, *magic, *program;
	int	type;
#ifdef XVIEW3
	Xv_notice	notice;
#endif

	xv_set(tool_property_window.frame,
		FRAME_LEFT_FOOTER, "",
		NULL);
	extension = (char *)xv_get(tool_property_window.viewers.extension,
	    PANEL_VALUE);
	if (*extension == '\0') {
		xv_set(tool_property_window.frame,
			FRAME_SHOW_FOOTER, TRUE,
			FRAME_LEFT_FOOTER, "Please specify an extension.",
			NULL);
		return;
	}
	magic = (char *)xv_get(tool_property_window.viewers.magic, PANEL_VALUE);
	program = (char *)xv_get(tool_property_window.viewers.program,
	    PANEL_VALUE);
	if (*program == '\0') {
		xv_set(tool_property_window.frame,
			FRAME_SHOW_FOOTER, TRUE,
			FRAME_LEFT_FOOTER, "Please specify a program to run.",
			NULL);
		return;
	}
	type = xv_get(tool_property_window.viewers.type, PANEL_VALUE);

	if (extension_exists(extension_list, extension)) {
		if (warnchange) {
#ifdef XVIEW3
			notice = xv_create(tool_property_window.viewers.panel,
				NOTICE,
				NOTICE_MESSAGE_STRINGS,
					"That extension exists. Do you really want to change it?",
					NULL,
				NOTICE_BUTTON_YES, "Yes",
				NOTICE_BUTTON_NO, "No",
				NOTICE_STATUS, &answer,
				XV_SHOW, TRUE,
				NULL);
			xv_destroy_safe(notice);
#else
			answer = notice_prompt(
			    tool_property_window.viewers.panel, NULL,
				NOTICE_MESSAGE_STRINGS,
					"That extension exists. Do you really want to change it?",
					NULL,
				NOTICE_BUTTON_YES, "Yes",
				NOTICE_BUTTON_NO, "No",
				NULL);
#endif
			if (answer != NOTICE_YES)
				return;
		}
		delete_extension(extension_list, extension);
	}
	extensions_changed = 1;
	add_extension(extension_list, extension, magic, program, type);
	clear_extension_list(tool_property_window.viewers.list);
	load_extension_list(extension_list, tool_property_window.viewers.list);
}

#ifdef USE_PROTOTYPES
void delete_extension(struct extension_info *head, char *extension)
#else
void delete_extension(head, extension)
struct extension_info *head;
char	*extension;
#endif
{
	struct extension_info *tmp, *deleted;

	for (tmp = head; tmp->next != NULL; tmp = tmp->next)
		if (!strcmp(extension, tmp->next->extension)) {
			deleted = tmp->next;
			tmp->next = deleted->next;
			deleted->next = NULL;
			free_extension(deleted);
			extensions_changed = 1;
			return;
		}
}

#ifdef USE_PROTOTYPES
int extension_exists(struct extension_info *head, char *extension)
#else
int extension_exists(head, extension)
struct extension_info *head;
char	*extension;
#endif
{
	struct extension_info *tmp;

	for (tmp = head->next; tmp != NULL; tmp = tmp->next)
		if (!strcmp(extension, tmp->extension))
			return (1);
	return (0);
}

#ifdef USE_PROTOTYPES
void uncompress(char *filename)
#else
void uncompress(filename)
char	*filename;
#endif
{
	char	*uncompressor;
	struct extension_info *ext_info;
	char	**argv;

	ext_info = type_by_either(filename);
	if (ext_info != NULL) {
		if (ext_info->type != FILE_DECOMPRESSOR) {
			local_footer_message("%s is not compressed.\n",
			    filename);
			return;
		}
		uncompressor = ext_info->program;
	} else {
		local_footer_message("Unknown file type, cannot decompress.\n");
		return;
	}
	argv = build_argv(uncompressor, filename);
	pipe_program(argv);
	free_argv(argv);
}

#ifdef USE_PROTOTYPES
void compress(char *filename)
#else
void compress(filename)
char	*filename;
#endif
{
	char	**argv;

	argv = build_argv(default_compressor, filename);
	pipe_program(argv);
	free_argv(argv);
}


syntax highlighted by Code2HTML, v. 0.9.1