/*
**  Copyright 2000-2004 University of Illinois Board of Trustees
**  Copyright 2000-2004 Mark D. Roth
**  All rights reserved.
**
**  ftpops.c - miscellaneous FTP operations
**
**  Mark D. Roth <roth@feep.net>
*/

#include <internal.h>

#include <errno.h>

#ifdef STDC_HEADERS
# include <string.h>
#endif


/* set TYPE for data connection */
int
ftp_type(FTP *ftp, char *type)
{
	char buf[FTPBUFSIZE];
	int code;

	/*
	** if we've already asked for the right type,
	** nothing needs to be done
	*/
	if (strcmp(ftp->ftp_type, type) == 0)
		return 0;

	/* send TYPE command */
	if (_ftp_send_command(ftp, "TYPE %s", type) == -1
	    || _ftp_get_response(ftp, &code, buf, sizeof(buf)) == -1)
		return -1;

	/* check response code */
	if (code != 200)
	{
		if (code == 421)
			errno = ECONNRESET;
		else
			errno = EINVAL;
		return -1;
	}

	/* save new type setting */
	strlcpy(ftp->ftp_type, type, sizeof(ftp->ftp_type));
	return 0;
}


/* rename a file */
int
ftp_rename(FTP *ftp, char *oldname, char *newname)
{
	int code;
	char buf[FTPBUFSIZE];

	if (_ftp_send_command(ftp, "RNFR %s", oldname) == -1
	    || _ftp_get_response(ftp, &code, buf, sizeof(buf)) == -1)
		return -1;
	if (code != 350)
	{
		if (code == 421)
			errno = ECONNRESET;
		else if (code == 450)
			errno = ETXTBSY;
		else if (code == 550)
			errno = ENOENT;
		else if (code == 530)
			errno = EACCES;
		else
			errno = EINVAL;
		return -1;
	}

	if (_ftp_send_command(ftp, "RNTO %s", newname) == -1
	    || _ftp_get_response(ftp, &code, buf, sizeof(buf)) == -1)
		return -1;
	if (code != 250)
	{
		if (code == 421)
			errno = ECONNRESET;
		else
			errno = EINVAL;
		return -1;
	}

	return 0;
}


/* remove a file or directory */
int
ftp_remove(FTP *ftp, char *path)
{
	struct ftpstat fs;

	if (ftp_lstat(ftp, path, &fs) == -1)
		return -1;

	return (S_ISDIR(fs.fs_mode)
		? ftp_rmdir(ftp, path)
		: ftp_unlink(ftp, path));
}


/* remove a file */
int
ftp_unlink(FTP *ftp, char *file)
{
	int code;
	char buf[FTPBUFSIZE];

	if (_ftp_send_command(ftp, "DELE %s", file) == -1
	    || _ftp_get_response(ftp, &code, buf, sizeof(buf)) == -1)
		return -1;
	if (code != 250)
	{
		if (code == 421)
			errno = ECONNRESET;
		else if (code == 550)
			errno = ENOENT;
		else if (code == 530)
			errno = EACCES;
		else if (code == 450)
			errno = ETXTBSY;
		else
			errno = EINVAL;
		return -1;
	}

	return 0;
}


/* determine the remote system type */
char *
ftp_systype(FTP *ftp)
{
	int code;
	char buf[FTPBUFSIZE];
	char *cp;

	if (ftp->ftp_systype[0] != 0)
		return ftp->ftp_systype;

	if (_ftp_send_command(ftp, "SYST") == -1
	    || _ftp_get_response(ftp, &code, buf, sizeof(buf)) == -1)
		return NULL;

	if (code == 215)
	{
		if ((cp = strchr(buf, ' ')) != NULL)
			*cp = '\0';
		strlcpy(ftp->ftp_systype, buf, sizeof(ftp->ftp_systype));
	}
	else if (code == 500)
		strlcpy(ftp->ftp_systype, "Unknown", sizeof(ftp->ftp_systype));
	else
	{
		if (code == 421)
			errno = ECONNRESET;
		else
			errno = EINVAL;
		return NULL;
	}

	return ftp->ftp_systype;
}


/* get server status */
int
ftp_status(FTP *ftp, char *buf, size_t bufsize)
{
	int code;

	if (_ftp_send_command(ftp, "STAT") == -1
	    || _ftp_get_response(ftp, &code, buf, bufsize) == -1)
		return -1;

	if (code != 211)
	{
		if (code == 421)
			errno = ECONNRESET;
		else
			errno = EINVAL;
		return -1;
	}

	return 0;
}


/* get current directory */
static char *
_ftp_pwd(FTP *ftp)
{
	int code;
	char buf[FTPBUFSIZE];
	char *cp1, *cp2;

	if (_ftp_send_command(ftp, "PWD") == -1
	    || _ftp_get_response(ftp, &code, buf, sizeof(buf)) == -1)
		return NULL;

	if (code != 257)
	{
		if (code == 421)
			errno = ECONNRESET;
		else if (code == 550)
			errno = ENOENT;
		else
			errno = EINVAL;
		return NULL;
	}

	if ((cp1 = strchr(buf, '"')) != NULL
	    && (cp2 = strchr(++cp1, '"')) != NULL)
	{
		*cp2 = '\0';
		strlcpy(ftp->ftp_dir, cp1, sizeof(ftp->ftp_dir));
		return ftp->ftp_dir;
	}

	errno = EINVAL;
	return NULL;
}


/* return current directory */
char *
ftp_getcwd(FTP *ftp)
{
	if (ftp->ftp_dir[0] != '\0')
		return ftp->ftp_dir;
	return _ftp_pwd(ftp);
}


/* change directory */
int
ftp_chdir(FTP *ftp, char *dir)
{
	int code;
	char buf[FTPBUFSIZE];

	if (_ftp_send_command(ftp, "CWD %s", dir) == -1
	    || _ftp_get_response(ftp, &code, buf, sizeof(buf)) == -1)
		return -1;

	if (code != 250)
	{
		if (code == 421)
			errno = ECONNRESET;
		else if (code == 530)
			errno = EACCES;
		else if (code == 550)
		{
			/*
			** the server returns the same response code
			** for ENOENT and ENOTDIR, so let's try to
			** guess which one it really means
			*/
			if (strstr(buf, "Not a directory") != NULL)
				errno = ENOTDIR;
			else
				errno = ENOENT;
		}
		else
			errno = EINVAL;
		return -1;
	}

	/* make sure we update our cached copy */
	if (_ftp_pwd(ftp) == NULL)
		return -1;

	return 0;
}


/* make a directory */
int
ftp_mkdir(FTP *ftp, char *dir)
{
	int code;
	char buf[FTPBUFSIZE];

	if (_ftp_send_command(ftp, "MKD %s", dir) == -1
	    || _ftp_get_response(ftp, &code, buf, sizeof(buf)) == -1)
		return -1;

	if (code != 257)
	{
		if (code == 421)
			errno = ECONNRESET;
		else if (code == 530)
			errno = EACCES;
		else if (code == 550)
			errno = ENOENT;
		else
			errno = EINVAL;
		return -1;
	}

	return 0;
}


/* remove a directory */
int
ftp_rmdir(FTP *ftp, char *dir)
{
	int code;
	char buf[FTPBUFSIZE];

	if (_ftp_send_command(ftp, "RMD %s", dir) == -1
	    || _ftp_get_response(ftp, &code, buf, sizeof(buf)) == -1)
		return -1;

	if (code != 250)
	{
		if (code == 421)
			errno = ECONNRESET;
		else if (code == 530)
			errno = EACCES;
		else if (code == 550)
			errno = ENOENT;
		else
			errno = EINVAL;
		return -1;
	}

	return 0;
}




syntax highlighted by Code2HTML, v. 0.9.1