#include "std.h"
#include "ftp.h"
#include "sutils.h"
#include "conf.h"

#include <pspiofilemgr.h>
#include <pspiofilemgr_fcntl.h>
#include <pspiofilemgr_stat.h>
#include <pspiofilemgr_dirent.h>
#include "psp_init.h"

int
mftpCreateDirIfNeeded(MftpConnection *con, char *Filename) 
{
	SceIoStat fileStats;

  char  DirPath[MAX_PATH_LENGTH];
  char *ScanDir;
  char *EndDir;

  strcpy(DirPath, Filename);
  EndDir  = strrchr(DirPath, '/');
  if (EndDir == (char *)0) return 0;
  EndDir[1] = '\0';

  /* Skip first slash */
  ScanDir  = DirPath;
  ScanDir  = strchr(ScanDir,'/');
  if (ScanDir == (char *)0) return 0;
  ScanDir = ScanDir + 1;
  
  while ( (EndDir = strchr(ScanDir,'/')) != (char *)0 ) {
    *EndDir = '\0';
    
		if (sceIoGetstat(DirPath, &fileStats) >= 0) {
		  if (!FIO_SO_ISDIR(fileStats.st_attr)) {
        return -1;
      }

    } else {
      sceIoMkdir(DirPath, 0);
      sceKernelDelayThread(100000); 
    }
    *EndDir = '/';
    ScanDir = EndDir + 1;
  }
  return 0;
}

void 
sendResponse(MftpConnection *con, char* s) 
{
	strcat(con->sockCommandBuffer, s);
	if (endsWith(con->sockCommandBuffer, "\n")) {
		sceNetInetSend(con->sockCommand, con->sockCommandBuffer, strlen(con->sockCommandBuffer) , 0);
		strcpy(con->sockCommandBuffer, "");
	}
}

void sendResponseLn(MftpConnection *con, char* s) 
{
	strcat(con->sockCommandBuffer, s);
	strcat(con->sockCommandBuffer, "\r\n");
	sceNetInetSend(con->sockCommand, con->sockCommandBuffer, strlen(con->sockCommandBuffer) , 0);
	strcpy(con->sockCommandBuffer, "");
}

void sendData(MftpConnection *con, char* s) 
{
	strcat(con->sockDataBuffer, s);
	if (endsWith(con->sockDataBuffer, "\n")) {
		sceNetInetSend(con->sockData, con->sockDataBuffer, strlen(con->sockDataBuffer) , 0);
		strcpy(con->sockDataBuffer, "");
	}
}

void 
sendDataLn(MftpConnection *con, char* s) {
	strcat(con->sockDataBuffer, s);
	strcat(con->sockDataBuffer, "\r\n");
	sceNetInetSend(con->sockData, con->sockDataBuffer, strlen(con->sockDataBuffer) , 0);
	strcpy(con->sockDataBuffer, "");
}

unsigned short pasvPort=59735;
int 
openDataConnectionPASV(MftpConnection *con) 
{
	con->usePassiveMode=1;

	int err;

	struct sockaddr_in addrPort;
	memset(&addrPort, 0, sizeof(struct sockaddr_in));

	addrPort.sin_reserved = sizeof(struct sockaddr_in);
	addrPort.sin_family = AF_INET;
	addrPort.sin_port = htons(pasvPort);
	addrPort.sin_addr[0] = 0;
	addrPort.sin_addr[1] = 0;
	addrPort.sin_addr[2] = 0;
	addrPort.sin_addr[3] = 0;

	con->sockPASV = sceNetInetSocket(AF_INET, SOCK_STREAM, 0);
	if (con->sockPASV & 0x80000000) return 0;

	err = sceNetInetBind(con->sockPASV, &addrPort, sizeof(addrPort));
	if (err) return 0;

	err = sceNetInetListen(con->sockPASV, 1);
	if (err) return 0;

	pasvPort++;
	return 0;
}


int openDataConnection(MftpConnection *con) {
	int err;

	if (con->usePassiveMode) {
		struct sockaddr_in addrAccept;
		u32 cbAddrAccept;

		cbAddrAccept = sizeof(addrAccept);
		con->sockData = sceNetInetAccept(con->sockPASV, &addrAccept, &cbAddrAccept);
		if (con->sockData & 0x80000000) return 0;
	} else {
		struct sockaddr_in addrPort;
		memset(&addrPort, 0, sizeof(struct sockaddr_in));

		addrPort.sin_reserved = sizeof(struct sockaddr_in);
		addrPort.sin_family = AF_INET;
		addrPort.sin_port = htons(con->port_port);
		addrPort.sin_addr[0] = con->port_addr[0];
		addrPort.sin_addr[1] = con->port_addr[1];
		addrPort.sin_addr[2] = con->port_addr[2];
		addrPort.sin_addr[3] = con->port_addr[3];

		con->sockData = sceNetInetSocket(AF_INET, SOCK_STREAM, 0);
		if (con->sockData & 0x80000000) return 0;

		err = sceNetInetConnect(con->sockData, &addrPort, sizeof(struct sockaddr_in));

		if (err) return 0;
	}

	return 1;
}

int 
closeDataConnection(MftpConnection *con) {
	int err = 0;

	err |= sceNetInetClose(con->sockData);
	if (con->usePassiveMode) {
		err |= sceNetInetClose(con->sockPASV);
	}

	if (err) return 0; else return 1;
}

int mftpServerHello(MftpConnection *con) {
	sendResponseLn(con, "220 FTP Server Ready");
	return 0;
}

int mftpCommandPWD(MftpConnection *con, char* command) 
{
	if (mftpRestrictedCommand(con,command)) {
		sendResponse(con, "257 \"");
		sendResponse(con, con->curDir);
		sendResponseLn(con, "\" is current directory.");
	}

	return 0;
}

int mftpCommandCWD(MftpConnection *con, char* command) 
{
	if (mftpRestrictedCommand(con,command)) {
		char* newDir=skipWS(&command[3]);
		trimEndingWS(newDir);

		char parsedDir[MAX_PATH_LENGTH+1];

		char* pParsedDir=parsedDir;
		parsedDir[0]=0;


		char* parser=newDir;
		if ((*newDir)=='/') {
			strcpy(con->curDir,"/");
			parser++;
		}

		do {
			if ((*parser)==0 || (*parser)=='/') {
				*pParsedDir=0;
				if (strcmp(parsedDir,".")==0) {

				} else if (strcmp(parsedDir,"..")==0) {
					char* pUp=con->curDir+strlen(con->curDir)-2;
					while ( pUp>=con->curDir && (*pUp)!='/' ) {
						pUp--;
					}
					if ((++pUp)>=con->curDir) {
						*pUp=0;
					}
					if (con->curDir[0]==0) {
						break;
					}

				} else {
					strcat(con->curDir, parsedDir);
		      if (!endsWith(con->curDir,"/")) {
			      strcat(con->curDir, "/");
		      }
				}
				pParsedDir=parsedDir;
			} else {
				(*pParsedDir++)=(*parser);
			}

		} while (*(parser++)!=0);
		
		if (!endsWith(con->curDir,"/")) {
			strcat(con->curDir, "/");
		}

		sendResponseLn(con, "250 CWD command successful.");
	}

	return 0;
}

int mftpCommandLIST(MftpConnection *con, char* command) 
{
	if (mftpRestrictedCommand(con,command)) {
		if (openDataConnection(con)==0) {
			sendResponseLn(con, "425 impossible to open data connection.");
		} else {
			sendResponseLn(con, "150 Opening ASCII mode data connection for file list");

			char path[MAX_PATH_LENGTH+1];
			strcpy(path, con->root);
			strcat(path, con->curDir);

			int ret,fd;

			//char *memid;

			SceIoDirent curFile;

			fd = sceIoDopen(path);
			if (fd>0) {
				do {
					//memset(&curFile, 0, sizeof(SceIoDirent));

					//memid = sceKernelAllocPartitionMemory(2, "myCurFile", 0, sizeof(SceIoDirent), NULL);

					ret = sceIoDread(fd, &curFile);
					
					char sInt[16]; strcpy(sInt,"");

					if (ret>0) {
						if (FIO_S_ISDIR(curFile.d_stat.st_mode)) {

							sendData(con, "drwxrwxrwx   2 root     root     ");
							itoa(sInt, curFile.d_stat.st_size);
							sendData(con, sInt);
							sendData(con, " Jan 01  1970 ");
							sendDataLn(con, curFile.d_name);

						} else if (FIO_S_ISLNK(curFile.d_stat.st_mode)) {
							sendData(con, "lrwxrwxrwx   1 root     root     ");
							itoa(sInt, curFile.d_stat.st_size);
							sendData(con, sInt);
							sendData(con, " Jan 01  1970 ");
							sendData(con, curFile.d_name);
							sendData(con, " -> ");
							sendDataLn(con, "???");
						} else {
							sendData(con, "-rwxrwxrwx   1 root     root     ");
							itoa(sInt, curFile.d_stat.st_size);
							sendData(con, sInt);
							sendData(con, " Jan 01  1970 ");
							sendDataLn(con, curFile.d_name);
						}
					}
				} while (ret>0);

				sceIoDclose(fd);
				//mallochedram = sceKernelGetBlockHeadAddr(memid);
				//sceKernelFreePartitionMemory(memid);
			}
			sendResponseLn(con, "226 Transfer complete.");
			closeDataConnection(con);
		}
	}

	return 0;
}

int mftpCommandNLST(MftpConnection *con, char* command) 
{
	if (mftpRestrictedCommand(con, command)) {
		if (openDataConnection(con)==0) {
			sendResponseLn(con, "425 impossible to open data connection.");
		} else {
			sendResponseLn(con, "150 Opening ASCII mode data connection for file list");

			char path[MAX_PATH_LENGTH+1];
			strcpy(path, con->root);
			strcat(path, con->curDir);

			int ret,fd;
			SceIoDirent curFile;

			fd = sceIoDopen(path);
			if (fd>0) {
				do {
					memset(&curFile, 0, sizeof(SceIoDirent));

					ret = sceIoDread(fd, &curFile);
					
					sendDataLn(con, curFile.d_name);
				} while (ret>0);

				sceIoDclose(fd);
			}

			sendResponseLn(con, "226 Transfer complete.");
			closeDataConnection(con);
		}
	}

	return 0;
}

int mftpCommandRETR(MftpConnection *con, char* command) 
{
	if (mftpRestrictedCommand(con, command)) {
		if (openDataConnection(con)==0) {
			sendResponseLn(con, "425 impossible to open data connection.");
		} else {
			char* fileName=skipWS(&command[5]);
			trimEndingWS(fileName);

			if (strlen(fileName)>0) {
				sendResponse(con, "150 Opening ASCII mode data connection for ");
				//TODO.txt (1805 bytes).
				sendResponse(con, fileName);
				sendResponseLn(con, ".");

				char filePath[MAX_PATH_LENGTH];
				if (strStartsWith(fileName, "/")) {
					strcpy(filePath, con->root);
					strcat(filePath, fileName);
				} else {
					strcpy(filePath, con->root);
					strcat(filePath, con->curDir);
					strcat(filePath, fileName);
				}

				SceIoStat fileStats;
				sceIoGetstat(filePath, &fileStats);

			  if ((! FIO_SO_ISDIR(fileStats.st_attr)) &&
            (! FIO_SO_ISLNK(fileStats.st_attr))) {
					int fdFile = sceIoOpen(filePath, PSP_O_RDONLY, 0777);

					char buf[TRANSFER_SEND_BUFFER_SIZE];
					int c=0;
					while ((c=sceIoRead(fdFile, buf, TRANSFER_SEND_BUFFER_SIZE))>0) {
						sceNetInetSend(con->sockData, buf, c , 0);
					}

					sceIoClose(fdFile);
					sendResponseLn(con, "226 Transfer complete.");
				} else {
					sendResponse(con, "550 ");
					sendResponse(con, fileName);
					sendResponseLn(con, ": not a regular file.");
				}
			} else {
				sendResponseLn(con, "500 'RETR': command requires a parameter.");
			}

			
			closeDataConnection(con);
		}
	}

	return 0;
}

int mftpCommandSTOR(MftpConnection *con, char* command) 
{
	if (mftpRestrictedCommand(con, command)) {
		if (openDataConnection(con)==0) {
			sendResponseLn(con, "425 impossible to open data connection.");
		} else {			
			char* fileName=skipWS(&command[5]);
			trimEndingWS(fileName);

			if (strlen(fileName)>0) {
				sendResponse(con, "150 Opening ASCII mode data connection for ");
				//TODO.txt (1805 bytes).
				sendResponse(con, fileName);
				sendResponseLn(con, ".");
				
				char filePath[MAX_PATH_LENGTH];
				if (strStartsWith(fileName, "/")) {
					strcpy(filePath, con->root);
					strcat(filePath, fileName);
				} else {
					strcpy(filePath, con->root);
					strcat(filePath, con->curDir);
					strcat(filePath, fileName);
				}

        if (mftpCreateDirIfNeeded(con, filePath) < 0) {
				  sendResponseLn(con, "552 'STOR': Requested file action aborted.");
        } else {
				  int fdFile = sceIoOpen(filePath, PSP_O_WRONLY | PSP_O_CREAT | PSP_O_TRUNC, 0777);

				  u8 buf[TRANSFER_RECV_BUFFER_SIZE];
          u8  write_buf[TRANSFER_WRITE_BUFFER_SIZE];
          int write_buf_length= 0;
				  int c=0;
				  while ((c=sceNetInetRecv(con->sockData, (u8*)buf, TRANSFER_RECV_BUFFER_SIZE, 0))>0) {
             if ((write_buf_length + c) >= TRANSFER_WRITE_BUFFER_SIZE) {
					     sceIoWrite(fdFile, write_buf, write_buf_length); 
               write_buf_length = 0;
             }
             memcpy(write_buf + write_buf_length,buf,c);
             write_buf_length += c;
				  }
          if (write_buf_length) {
					  sceIoWrite(fdFile, write_buf, write_buf_length); 
            write_buf_length = 0;
          }

				  sceIoClose(fdFile);
				  closeDataConnection(con);
				  sendResponseLn(con, "226 Transfer complete.");
        }
         
			} else {
				sendResponseLn(con, "500 'STOR': command requires a parameter.");
				closeDataConnection(con);
			}

		}
	}

	return 0;
}

int mftpCommandSIZE(MftpConnection *con, char* command) 
{
	if (mftpRestrictedCommand(con, command)) {
		char* fileName=skipWS(&command[5]);
		trimEndingWS(fileName);

		if (strlen(fileName)>0) {
			char filePath[MAX_PATH_LENGTH];
			if (strStartsWith(fileName, "/")) {
				strcpy(filePath, con->root);
				strcat(filePath, fileName);
			} else {
				strcpy(filePath, con->root);
				strcat(filePath, con->curDir);
				strcat(filePath, fileName);
			}

			SceIoStat fileStats;
			sceIoGetstat(filePath, &fileStats);

			if ((! FIO_SO_ISDIR(fileStats.st_attr)) &&
          (! FIO_SO_ISLNK(fileStats.st_attr))) {
				char tmp[32];
				itoa(tmp, fileStats.st_size);
				sendResponse(con, "213 ");
				sendResponseLn(con, tmp);
			} else {
				sendResponse(con, "550 ");
				sendResponse(con, fileName);
				sendResponseLn(con, ": not a regular file.");
			}
			
		} else {
			sendResponseLn(con, "500 'SIZE': command requires a parameter.");
		}
	}

	return 0;
}

int mftpCommandDELE(MftpConnection *con, char* command) 
{
	if (mftpRestrictedCommand(con, command)) {
		char* fileName=skipWS(&command[5]);
		trimEndingWS(fileName);

		if (strlen(fileName)>0) {

			char filePath[MAX_PATH_LENGTH];
			if (strStartsWith(fileName, "/")) {
				strcpy(filePath, con->root);
				strcat(filePath, fileName);
			} else {
				strcpy(filePath, con->root);
				strcat(filePath, con->curDir);
				strcat(filePath, fileName);
			}

			sceIoRemove(filePath);

			sendResponseLn(con, "250 DELE command successful.");
		} else {
			sendResponseLn(con, "500 'DELE': command requires a parameter.");
		}
	}

	return 0;
}

int mftpCommandRMD(MftpConnection *con, char* command) 
{
	if (mftpRestrictedCommand(con, command)) {
		char* fileName=skipWS(&command[4]);
		trimEndingWS(fileName);

		if (strlen(fileName)>0) {

			char filePath[MAX_PATH_LENGTH];
			if (strStartsWith(fileName, "/")) {
				strcpy(filePath, con->root);
				strcat(filePath, fileName);
			} else {
				strcpy(filePath, con->root);
				strcat(filePath, con->curDir);
				strcat(filePath, fileName);
			}

			trimEndingChar(filePath, '/');
			sceIoRmdir(filePath);
      sceKernelDelayThread(100000); 
			sendResponseLn(con, "250 RMD command successful.");
		} else {
			sendResponseLn(con, "500 'RMD': command requires a parameter.");
		}
	}

	return 0;
}

int mftpCommandMKD(MftpConnection *con, char* command) 
{
	if (mftpRestrictedCommand(con, command)) {
		char* fileName=skipWS(&command[4]);
		trimEndingWS(fileName);

		if (strlen(fileName)>0) {

			char filePath[MAX_PATH_LENGTH];
			if (strStartsWith(fileName, "/")) {
				strcpy(filePath, con->root);
				strcat(filePath, fileName);
			} else {
				strcpy(filePath, con->root);
				strcat(filePath, con->curDir);
				strcat(filePath, fileName);
			}

			trimEndingChar(filePath, '/');

      if (mftpCreateDirIfNeeded(con, filePath) < 0) {
			  sendResponseLn(con, "552 'MKD': Requested file action aborted.");
      } else {
			  sceIoMkdir(filePath, 0);
        sceKernelDelayThread(100000); 
       
			  sendResponse(con, "257 \"");
			  sendResponse(con, fileName);
			  sendResponseLn(con, "\" - Directory successfully created.");
      }
		} else {
			sendResponseLn(con, "500 'MKD': command requires a parameter.");
		}
	}

	return 0;
}

int mftpCommandHELP(MftpConnection *con, char* command) 
{
	sendResponseLn(con, "214-The following commands are recognized (* =>'s unimplemented).");
	sendResponseLn(con, "214-USER    PASS    ACCT*   CWD     XCWD*    CDUP    XCUP*    SMNT*");
	sendResponseLn(con, "214-QUIT    REIN*   PORT    PASV    TYPE    STRU*    MODE*    RETR");
	sendResponseLn(con, "214-STOR    STOU*   APPE*    ALLO*   REST*    RNFR     RNTO     ABOR*");
	sendResponseLn(con, "214-DELE    MDTM*    RMD     XRMD*    MKD     XMKD*    PWD     XPWD*");
	sendResponseLn(con, "214-SIZE    LIST    NLST    SITE    SYST    STAT*    HELP    NOOP");
	sendResponseLn(con, "214 Direct comments to psp@amoks.com.");

	return 0;
}

int mftpCommandSITE(MftpConnection *con, char * command) 
{
	char* param=skipWS(&command[5]);
	trimEndingWS(param);
	toUpperCase(param);
	if (strcmp(param, "HELP")==0) {
		sendResponseLn(con, "214-The following SITE commands are recognized (* =>'s unimplemented).");
		sendResponseLn(con, "214-HELP");
		sendResponseLn(con, "214 Direct comments to psp@amoks.com.");
	} else if (strlen(param)==0) {
		sendResponseLn(con, "500 'SITE' requires argument.");
	} else {
		sendResponse(con, "500 '");
		sendResponse(con, command);
		sendResponseLn(con, "' not understood.");
	}

	return 0;
}

int mftpCommandPORT(MftpConnection *con, char* command) 
{
	int params[6];
	char decimByte[4];
	char* pDecimByte=decimByte;
	char* pParams=skipWS(&command[5]);

	int state=0; int err=0; int nbParams=0;
	do {
		if (state==0 && *pParams>='0' && *pParams<='9') {
			state=1;
			pParams--;
		} else if (state==1 && *pParams>='0' && *pParams<='9') {
			if (pDecimByte-decimByte<=2) {
				*(pDecimByte++)=*pParams;
			} else {
				err=1;
			}
		} else if (state==1 && (*pParams==',' || *pParams==0) && nbParams<6) {
			*pDecimByte=0;

			if (strlen(decimByte)==0) {
				err=1;
			} else {
				int param=0;
				char* tmp=decimByte+strlen(decimByte)-1;
				int pow=1;
				while (tmp>=decimByte && err==0) {
					
					if (*tmp>='0' && *tmp<='9') {
						param+= ((*tmp)-48)*pow;
						pow=pow*10;
					} else {
						err=1;
					}

					tmp--;
				}

				if (err==0) {
					params[nbParams++]=param;
					pDecimByte=decimByte;
				}
			}
		} else {
			err=1;
		}

	} while (*(pParams++)!=0 && err==0);

	if (err==0 && state==1 && nbParams==6) {
		con->usePassiveMode=0;

		con->port_addr[0]=(unsigned char) params[0];
		con->port_addr[1]=(unsigned char) params[1];
		con->port_addr[2]=(unsigned char) params[2];
		con->port_addr[3]=(unsigned char) params[3];
		con->port_port=((unsigned char) params[4]<<8) | ((unsigned char) params[5]);
		sendResponseLn(con, "200 PORT command successful.");
	} else {
		con->port_addr[0]=0;
		con->port_addr[1]=0;
		con->port_addr[2]=0;
		con->port_addr[3]=0;
		con->port_port=0;
		sendResponseLn(con, "500 illegal PORT command.");
	}

	return 0;
}

int mftpCommandUSER(MftpConnection *con, char* command) 
{
	if (con->userLoggedIn) {
		sendResponseLn(con, "503 You are already logged in!");
	} else {
		con->user[0]=0;
		con->pass[0]=0;
		char* pUser=skipWS(&command[5]);
		trimEndingWS(pUser);
		if (strlen(pUser)==0) {
			sendResponseLn(con, "500 'USER': command requires a parameter.");
		} else {
			strncpy(con->user, pUser, MAX_USER_LENGTH);
			sendResponse(con, "331 Password required for ");
			sendResponse(con, con->user);
			sendResponseLn(con, ".");
		}
	}

	return 0;
}

CONFIGFILE config;

int mftpCommandPASS(MftpConnection *con, char* command) 
{

	if (con->userLoggedIn) {
		sendResponseLn(con, "503 You are already logged in!");
	} else {
		if (strlen(con->user)==0) {
			sendResponseLn(con, "503 Login with USER first.");
		} 
    else 
    {
			con->pass[0]=0;
			char* pPass=skipWS(&command[5]);
			trimEndingWS(pPass);
			if (strlen(pPass)==0) {
				sendResponseLn(con, "500 'PASS': command requires a parameter.");
			} else {
				strncpy(con->pass, pPass, MAX_PASS_LENGTH);
        //if (mftp_config.auth_required) {
	if (config.authEnable) {
          //mftpUser_t *CheckUser = cfg_get_user(con->user, con->pass);
          //if (CheckUser == (mftpUser_t *)0) {
	   if (strcmp(con->pass, config.password)) { 
					  sendResponseLn(con, "530 You're not allowed to log in.");
					  con->userLoggedIn=0;
					  con->user[0]=0; con->pass[0]=0;
            return 0;
          } else {
           // strcpy(con->root,CheckUser->root);
          }
        }
				sendResponseLn(con, "230 You're logged in.");
				con->userLoggedIn=1;
			}
		}
	}

	return 0;
}

int mftpCommandTYPE(MftpConnection *con, char* command) 
{
	if (mftpRestrictedCommand(con, command)) {
		char* pParam1=skipWS(&command[5]);
		trimEndingWS(pParam1);
		if (strlen(pParam1)==0) {
			sendResponseLn(con, "500 'TYPE': command requires a parameter.");
		} else if (strlen(pParam1)==1 && (*pParam1=='A' || *pParam1=='E' || *pParam1=='I' || *pParam1=='L')) {
			con->transfertType=*pParam1;
			sendResponse(con, "200 Type set to ");
			sendResponse(con, pParam1);
			sendResponseLn(con, ".");
		} else {
			sendResponseLn(con, "500 'TYPE': 2 parameters extended version not understood.");
		}
	}

	return 0;
}

int mftpCommandSYST(MftpConnection *con, char* command) 
{
	if (mftpRestrictedCommand(con, command)) {
		sendResponseLn(con, "215 UNIX Type: L8");
	}

	return 0;
}

int mftpCommandPASV(MftpConnection *con, char* command) 
{
	if (mftpRestrictedCommand(con, command)) {
		
		char tmp[32];
		strncpy(tmp, con->serverIp, 31);
		strReplaceChar(tmp, '.', ',');

		sendResponse(con, "227 Entering Passive Mode (");
		sendResponse(con, tmp);
		sendResponse(con, ",");
		itoa(tmp, (pasvPort>>8) & 0xFF);
		sendResponse(con, tmp);
		sendResponse(con, ",");
		itoa(tmp, pasvPort & 0xFF);
		sendResponse(con, tmp);
		sendResponseLn(con, ").");

		openDataConnectionPASV(con);
	}

	return 0;
}

int mftpCommandNOOP(MftpConnection *con, char* command) 
{
	if (mftpRestrictedCommand(con, command)) {
		sendResponseLn(con, "200 NOOP command successful.");
	}

	return 0;
}

int mftpCommandQUIT(MftpConnection *con, char* command) 
{
	closeDataConnection(con);

	return -1;
}

int mftpCommandRNFR(MftpConnection *con, char* command) 
{
	if (mftpRestrictedCommand(con, command)) {
		char* fileName=skipWS(&command[4]);
		trimEndingWS(fileName);

		if (strlen(fileName)>0) {

			char filePath[MAX_PATH_LENGTH];
			if (strStartsWith(fileName, "/")) {
				strcpy(filePath, con->root);
				strcat(filePath, fileName);
			} else {
				strcpy(filePath, con->root);
				strcat(filePath, con->curDir);
				strcat(filePath, fileName);
			}
 
      strncpy(con->renameFromFileName,filePath,MAX_PATH_LENGTH);

		  sendResponseLn(con, "350 File or directory exists, ready for destination name.");
      con->renameFrom = 1;
		} else {
			sendResponseLn(con, "500 'RNFR': command requires a parameter.");
      con->renameFrom = 0;
		}
	}

  return 0;
}

int mftpCommandRNTO(MftpConnection *con, char* command) 
{
  if (! con->renameFrom) {
	  sendResponseLn(con, "503 'RNTO': Bad sequence of commands.");
    return 0;
  }
  con->renameFrom = 0;

	if (mftpRestrictedCommand(con, command)) {
		char* fileName=skipWS(&command[4]);
		trimEndingWS(fileName);

    if (strlen(fileName)>0) {

			char filePath[MAX_PATH_LENGTH];
			if (strStartsWith(fileName, "/")) {
				strcpy(filePath, con->root);
				strcat(filePath, fileName);
			} else {
				strcpy(filePath, con->root);
				strcat(filePath, con->curDir);
				strcat(filePath, fileName);
			}

      sceIoRename(con->renameFromFileName,filePath);
		  sendResponseLn(con, "250 Rename successfull.");
		} else {
			sendResponseLn(con, "500 'RNTO': command requires a parameter.");
		}
	}

  return 0;
}

int mftpRestrictedCommand(MftpConnection *con, char* command) 
{
	/*if ((mftp_config.auth_required) && (!con->userLoggedIn)) {
		sendResponseLn(con, "530 Please login with USER and PASS.");
		return 0;
	} */
  return 1;
}

int mftpDispatch(MftpConnection *con, char* command) 
{
	char uCommand[MAX_COMMAND_LENGTH+1];
	strncpy(uCommand, command, MAX_COMMAND_LENGTH);
	toUpperCase(uCommand);
  int renameFrom = 0;

	int ret=0;
	if (strlen(uCommand)>0) {
		if (strcmp(uCommand, "PWD")==0) {
			ret=mftpCommandPWD(con, command);
		} else if (strcmp(uCommand, "NLST")==0) {
			ret=mftpCommandNLST(con, command);
		} else if (strcmp(uCommand, "LIST")==0 || strStartsWith(uCommand, "LIST ")) {
			ret=mftpCommandLIST(con, command);
		} else if (strStartsWith(uCommand, "RETR ")) {
			ret=mftpCommandRETR(con, command);
		} else if (strStartsWith(uCommand, "STOR ")) {
			ret=mftpCommandSTOR(con, command);
		} else if (strStartsWith(uCommand, "SIZE ")) {
			ret=mftpCommandSIZE(con, command);
		} else if (strStartsWith(uCommand, "DELE ")) {
			ret=mftpCommandDELE(con, command);
		} else if (strStartsWith(uCommand, "RMD ")) {
			ret=mftpCommandRMD(con, command);
		} else if (strStartsWith(uCommand, "MKD ")) {
			ret=mftpCommandMKD(con, command);
		} else if (strStartsWith(uCommand, "RNFR ")) {
			ret=mftpCommandRNFR(con, command);
      renameFrom = con->renameFrom;
		} else if (strStartsWith(uCommand, "RNTO ")) {
			ret=mftpCommandRNTO(con, command);
		} else if (strcmp(uCommand, "CDUP")==0) {
			ret=mftpCommandCWD(con, "CWD ..");
		} else if (strStartsWith(uCommand, "CWD ")) {
			ret=mftpCommandCWD(con, command);
		} else if (strcmp(uCommand, "HELP")==0 || strStartsWith(uCommand, "HELP ")) {
			ret=mftpCommandHELP(con, command);
		} else if (strcmp(uCommand, "SITE")==0 || strStartsWith(uCommand, "SITE ")) {
			ret=mftpCommandSITE(con, command);
		} else if (strStartsWith(uCommand, "PORT ")) {
			ret=mftpCommandPORT(con, command);
		} else if (strStartsWith(uCommand, "USER ")) {
			ret=mftpCommandUSER(con, command);
		} else if (strStartsWith(uCommand, "PASS ")) {
			ret=mftpCommandPASS(con, command);
		} else if (strStartsWith(uCommand, "TYPE ")) {
			ret=mftpCommandTYPE(con, command);
		} else if (strcmp(uCommand, "SYST")==0) {
			ret=mftpCommandSYST(con, command);
		} else if (strcmp(uCommand, "PASV")==0) {
			ret=mftpCommandPASV(con, command);
		} else if (strcmp(uCommand, "NOOP")==0) {
			ret=mftpCommandNOOP(con, command);
		} else if (strcmp(uCommand, "QUIT")==0) {
			ret=mftpCommandQUIT(con, command);
		} else {
			sendResponse(con, "500 ");
			sendResponse(con, command);
			sendResponseLn(con, " not understood.");
# ifdef DEBUG
      pspDebugPrintf("command not understood\n");
# endif
		}
    con->renameFrom = renameFrom;
	}

	return ret;
}
