// get the input string and involve the callback function static int ExecCmd(char *pszCmdLine) { if(NULL == pszCmdLine) return -1; if('\0' == *pszCmdLine){ return 0; //if command is NULL do not print error } unsigned int cmdLen = 0; unsigned int dwCmdIndex = 0; for(; dwCmdIndex < CMD_MAP_NUM; dwCmdIndex++) { if(gCmdMap[dwCmdIndex].pszCmd!=NULL){ cmdLen = strlen(gCmdMap[dwCmdIndex].pszCmd); if(!strncmp(pszCmdLine, gCmdMap[dwCmdIndex].pszCmd, cmdLen)){ if (*(pszCmdLine+cmdLen) != ' ' && *(pszCmdLine+cmdLen) != '\0'){ continue; } parse_input_cmd(pszCmdLine); break; } } } if(CMD_MAP_NUM == dwCmdIndex) return -1; gCmdMap[dwCmdIndex].fpCmd(); return 0; }
int main(int argc, char *argv[]) { int server_port = 2121; if (argc < 2) { printf("usage: %s <addr> [2121]\n", argv[0]); exit(0); } if (argc == 3) { server_port = atoi(argv[2]); } int client = new_client(ntohl(inet_addr(argv[1])), server_port); if (client < 0) { err(1, "can not connect to %s %d", argv[1], server_port); err(1, "exit ..."); exit(1); } int i, n; char buf[BUF_SIZE+1]; char tmpbuf[BUF_SIZE+1]; char cmdbuf[BUF_SIZE+1]; int data_client = -1; struct sockaddr_in data_client_addr; uint32_t addr; uint16_t port; char path[BUF_SIZE]; int code = -1; enum CLIENT_STATE state = ST_NONE; char filename[BUF_SIZE], line[BUF_SIZE]; while ((n=recv(client, buf, sizeof(buf), MSG_PEEK)) > 0) { if (!running) break; for (i=0; i<n; i++) { if (buf[i] == '\n') break; } if (buf[i] != '\n') { err(1, "no line break found"); break; } n = recv(client, buf, i+1, 0); buf[n] = 0; printf("%s", buf); fflush(stdout); parse_number(buf, &code); if (code < RPL_ERR_UNKWNCMD && state != ST_NONE) { switch(state) { case ST_PASVLIST: case ST_PASVGET: case ST_PASVPUT: if (code == RPL_PASVOK) { strcpy(tmpbuf, buf); tmpbuf[0] = tmpbuf[1] = tmpbuf[2] = tmpbuf[3] = ' '; parse_addr_port(tmpbuf, &addr, &port); switch(state) { case ST_PASVLIST: send_str(client, "LIST\r\n"); break; case ST_PASVGET: send_str(client, "RETR %s\r\n", filename); break; case ST_PASVPUT: send_str(client, "STOR %s\r\n", filename); break; } data_client = new_client(addr, port); state++; } else { state = ST_NONE; } break; case ST_PASVLIST2: case ST_PASVGET2: case ST_PASVPUT2: if (data_client < 0) { err(1, "data client not created"); } else { if (state == ST_PASVLIST2) { recv_file(data_client, stdout); } else if (state == ST_PASVGET2) { recv_path(data_client, filename, 0); } else if (state == ST_PASVPUT2) { FILE *f = fopen(filename, "rb"); if (f) { send_file(data_client, f); fclose(f); } else { err(1, "err open file %s", filename); } } info(1, "closing data socket ... %d", close(data_client)); data_client = -1; state = ST_NONE; } break; default: state = ST_NONE; break; } if (code < RPL_ERR_UNKWNCMD) continue; } if (code >= RPL_ERR_UNKWNCMD) state = ST_NONE; int valid = 0; while (!valid) { valid = 1; printf("ftp >>> "); if (!fgets(line, BUF_SIZE, stdin)){ running = 0; break; } int len = strlen(line); len --; while (line[len] == '\n' || line[len] == '\r') len--; len ++; line[len] = 0; enum USER_CMD cmd = parse_input_cmd(line, len); switch(cmd) { case USER_USER: case USER_PASS: case USER_TYPE: case USER_MKD: case USER_DELE: case USER_RNFR: case USER_RNTO: case USER_RMD: send_str(client, "%s\r\n", line); break; case USER_LS: send_str(client, "PASV\r\n"); state = ST_PASVLIST; break; case USER_CD: send_str(client, "CWD %s\r\n", &line[3]); break; case USER_PWD: send_str(client, "PWD\r\n"); break; case USER_CDUP: send_str(client, "CDUP\r\n"); break; case USER_HELP: for (i=0; i<sizeof(USER_CMD_LIST)/sizeof(USER_CMD_LIST[0]); i++) { printf("%s\n", USER_CMD_LIST[i].name); } valid = 0; break; case USER_BYE: send_str(client, "QUIT\r\n"); running = 0; break; case USER_LCD: chdir(&line[4]); valid = 0; break; case USER_LLS: getcwd(path, sizeof(path)); printf("%s\n", path); sprintf(cmdbuf, "ls -l %s", path); FILE *p2 = popen(cmdbuf, "r"); int n; while ((n=fread(tmpbuf, 1, BUF_SIZE, p2)) > 0 ) { fwrite(tmpbuf, 1, n, stdout); } pclose(p2); valid = 0; break; case USER_LPWD: getcwd(path, sizeof(path)); printf("%s\n", path); valid = 0; break; case USER_GET: send_str(client, "PASV\r\n"); strcpy(filename, &line[4]); state = ST_PASVGET; break; case USER_PUT: send_str(client, "PASV\r\n"); strcpy(filename, &line[4]); state = ST_PASVPUT; break; default: warn(1, "unknown user cmd"); valid = 0; break; } } if (!running) break; } int st = close(client); info(1, "FTP client close socket ... %d", st); info(1, "FTP client shutdown"); if (data_client > 0) { st = close(data_client); info(1, "FTP client close data socket ... %d", st); info(1, "FTP client data socket shutdown"); } return 0; }