/* client.cpp libftp++ C++ classes for ftplib C ftp library compile: clang++ -std=c++11 -o client client.cpp -lftp++ */ #include #include #include #include #include // stat #include // libftp #include // libftp++ /* C++ classes: Connection main ftp connection (user class) ConnectionBase base class for Connection (internal) DataConnection connection type, (internal) read bytes from server, write bytes to server ConnectionException custom exception (thrown by Connection) */ /** ftp::Connection class API data members: A Connection instance contains only a pointer as a data member { protected: netbuf * conn; // pointer to ftplib netbuf struct } member functions: connect: Connection(const char * host); // constructor void setConnectionMode(Mode mode); // passive or port void login(const char * user, const char * password); // Log in info: const char * getLastResponse(); // last server response std::string getSystemType(); // server type std::string getDirectory(); // remote pwd void getList(const char * filename, const char * path); // short dir list unsigned size(const char * path, TransferMode mode); file transfer: void get(const char * local, const char * remote, TransferMode mode); void put(const char * local, const char * remote, TransferMode mode); **/ // libc functions int stat(const char *pathname, struct stat *buf); // local file info char *strerror(int errnum); // explanation of error char *basename(char *path); // filename at end of path // STL classes and functions used namespace stl { using std::cout; // stdout using std::cerr; // stderr using std::string; // string using std::ifstream; // files on disk using std::remove; // delete file on disk }; using namespace stl; // connection modes using Mode = ftp::Connection::Mode; Mode PASV = Mode::PASSIVE; Mode PORT = Mode::PORT; //file transfer modes using TransferMode = ftp::Connection::TransferMode; TransferMode BINARY = TransferMode::BINARY; TransferMode TEXT = TransferMode::TEXT; /* ********************** */ // ftp session parameters struct session { const string server; // server name const string port; // usually 21 const string user; // username const string pass; // password Mode mode; // PASV, PORT TransferMode txmode; // BINARY, TEXT string dir; // current or default dir }; /* ********************** */ // local helper functions ftp::Connection connect_ftp( const session& sess); size_t get_ftp( ftp::Connection& conn, string const& path); string readFile( const string& filename); string login_ftp(ftp::Connection& conn, const session& sess); string dir_listing( ftp::Connection& conn, const string& path); /* ******************************** */ // Read a file into one long string string readFile( const string& filename) { struct stat stat_buf; string contents; errno = 0; if (stat(filename.c_str() , &stat_buf) != -1) // file stats { size_t len = stat_buf.st_size; // size of file string bytes(len+1, '\0'); // string big enough ifstream ifs(filename); // open for input ifs.read(&bytes[0], len); // read all bytes as chars into string if (! ifs.fail() ) contents.swap(bytes); // swap into contents ifs.close(); } else { cerr << "stat error: " << strerror(errno); } return contents; } /* *************** */ // start a session ftp::Connection connect_ftp( const session& sess) try { string constr = sess.server + ":" + sess.port; cerr << "connecting to " << constr << " ...\n"; ftp::Connection conn{ constr.c_str() }; cerr << "connected to " << constr << "\n"; conn.setConnectionMode(sess.mode); return conn; } catch (ftp::ConnectException e) { cerr << "FTP error: could not connect to server" << "\n"; } /* ***** */ // login string login_ftp(ftp::Connection& conn, const session& sess) { conn.login(sess.user.c_str() , sess.pass.c_str() ); return conn.getLastResponse(); } /* ***************************** */ // get remote directory listing // ftplib writes to file for dir contents // convert file contents to string string dir_listing( ftp::Connection& conn, const string& path) try { // file on disk to write to const char* dirdata = "/dev/shm/dirdata"; conn.getList(dirdata, path.c_str() ); // conn.getFullList(dirdata, path.c_str() ); // conn.getFullList(NULL, path.c_str() ); // to stdout string dir_string = readFile(dirdata); cerr << conn.getLastResponse() << "\n"; errno = 0; if ( remove(dirdata) != 0 ) // delete file on disk { cerr << "error: " << strerror(errno) << "\n"; } return dir_string; } catch (...) { cerr << "error: getting dir contents: \n" << strerror(errno) << "\n"; } /* ************************* */ // retrieve file from server size_t get_ftp( ftp::Connection& conn, const string& r_path) { size_t received = 0; const char* path = r_path.c_str(); unsigned remotefile_size = conn.size(path , BINARY); const char* localfile = basename(path); conn.get(localfile, path, BINARY); // get file cerr << conn.getLastResponse() << "\n"; // get local file size struct stat stat_buf; errno = 0; if (stat(localfile, &stat_buf) != -1) received = stat_buf.st_size; else cerr << strerror(errno); return received; } /* ******************** */ // default test session const session sonic { "mirrors.sonic.net", "21" , "anonymous", "xxxx@nohost.org", PASV, BINARY, "/pub/OpenBSD" }; /* **** */ // main int main(int argc, char* argv[], char * env[] ) { const session remote = sonic; // copy session info try { // open an ftp connection ftp::Connection conn = connect_ftp(remote); // login with username and passwd cerr << login_ftp(conn, remote); // what type system cout << "System type: " << conn.getSystemType() << "\n"; cerr << conn.getLastResponse() << "\n"; // cd to default session dir conn.cd(remote.dir.c_str()); // change to dir on server cerr << conn.getLastResponse() << "\n"; // get current remote directory string pwdstr = conn.getDirectory(); cout << "PWD: " << pwdstr << "\n"; cerr << conn.getLastResponse() << "\n"; // get file listing string dirlist = dir_listing(conn, pwdstr.c_str() ); cout << dirlist << "\n"; string filename = "ftplist"; // small text file auto pos = dirlist.find(filename); // find filename in dir list auto notfound = string::npos; if (pos != notfound) // found filename { // get file size_t received = get_ftp(conn, filename.c_str() ); if (received == 0) cerr << "got 0 bytes\n"; else cerr << "got " << filename << " (" << received << " bytes)\n"; } else { cerr << "file " << filename << "not found on server. \n"; } } catch (ftp::ConnectException e) { cerr << "FTP error: could not connect to server" << "\n"; } catch (ftp::Exception e) { cerr << "FTP error: " << e << "\n"; } catch (...) { cerr << "error: " << strerror(errno) << "\n"; } // logout, connection closes automatically when conn destructs return 0; } /* END */