Logo
  • Main Page
  • Related Pages
  • Modules
  • Classes
  • Files

mmsfiletransfer.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2005-2007 Stefan Schwarzer, Jens Schneider,             *
00003  *                           Matthias Hardt, Guido Madaus                  *
00004  *                                                                         *
00005  *   Copyright (C) 2007-2008 BerLinux Solutions GbR                        *
00006  *                           Stefan Schwarzer & Guido Madaus               *
00007  *                                                                         *
00008  *   Copyright (C) 2009-2013 BerLinux Solutions GmbH                       *
00009  *                                                                         *
00010  *   Authors:                                                              *
00011  *      Stefan Schwarzer   <stefan.schwarzer@diskohq.org>,                 *
00012  *      Matthias Hardt     <matthias.hardt@diskohq.org>,                   *
00013  *      Jens Schneider     <jens.schneider@diskohq.org>,                   *
00014  *      Guido Madaus       <guido.madaus@diskohq.org>,                     *
00015  *      Patrick Helterhoff <patrick.helterhoff@diskohq.org>,               *
00016  *      René Bählkow       <rene.baehlkow@diskohq.org>                     *
00017  *                                                                         *
00018  *   This library is free software; you can redistribute it and/or         *
00019  *   modify it under the terms of the GNU Lesser General Public            *
00020  *   License version 2.1 as published by the Free Software Foundation.     *
00021  *                                                                         *
00022  *   This library is distributed in the hope that it will be useful,       *
00023  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00024  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00025  *   Lesser General Public License for more details.                       *
00026  *                                                                         *
00027  *   You should have received a copy of the GNU Lesser General Public      *
00028  *   License along with this library; if not, write to the                 *
00029  *   Free Software Foundation, Inc.,                                       *
00030  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
00031  **************************************************************************/
00032 
00033 #ifdef __HAVE_CURL__
00034 #include "mmstools/mmsfiletransfer.h"
00035 #include <string.h>
00036 #include <stdlib.h>
00037 
00038 size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream) {
00039     return fread(ptr, size, nmemb, (FILE*) stream);
00040 }
00041 
00042 size_t write_callback(void *buffer, size_t size, size_t nmemb, void *stream) {
00043     FtpFile *out = (FtpFile*) stream;
00044     if (out && !out->stream) {
00045         /* open file for appending */
00046         out->stream = fopen(out->filename, "ab");
00047         if (!out->stream)
00048             return -1; /* failure, can't open file to write */
00049     }
00050 
00051     return fwrite(buffer, size, nmemb, out->stream);
00052 }
00053 
00054 
00055 /* curl calls this c-routine to transfer data to the object */
00056 size_t c_mem_write_callback(char *buffer, size_t size, size_t nitems, void *outstream) {
00057     if (outstream)
00058         return ((MMSFiletransfer *)outstream)->mem_write_callback(buffer, size, nitems, outstream);
00059     else
00060         return 0;
00061 }
00062 
00063 
00064 size_t MMSFiletransfer::mem_write_callback(char *buffer, size_t size, size_t nitems, void *outstream) {
00065     char            *newbuff;                  /* pointer to new buffer */
00066     unsigned int    freebuff;                  /* free memory in old buffer */
00067 
00068     /* get the byte number */
00069     size *= nitems;
00070 
00071     /* calculate free buffer space */
00072     freebuff=this->buf_len - this->buf_pos;
00073 
00074     if(size > freebuff) {
00075         /* not enough space in the old buffer */
00076         newbuff=(char*)realloc(this->buffer,this->buf_len + (size - freebuff));
00077         if(newbuff==NULL) {
00078             size=freebuff;
00079         }
00080         else {
00081             /* new buffer size */
00082             this->buf_len+=size - freebuff;
00083             this->buffer=newbuff;
00084         }
00085     }
00086 
00087     memcpy(&(this->buffer[this->buf_pos]), buffer, size);
00088     this->buf_pos += size;
00089 
00090     return size;
00091 }
00092 
00093 
00094 int progress_callback(void *pclient, double dltotal, double dlnow, double ultotal, double ulnow) {
00095     ((MMSFiletransfer*) pclient)->progress.emit(dltotal != 0 ? (int) (.5 + 100* dlnow / dltotal) : (int) (.5 + 100* ulnow / ultotal));
00096     return 0;
00097 }
00098 
00099 MMSFiletransfer::MMSFiletransfer(const string url, const unsigned int ftpPort = 0) :
00100     timeout(10),
00101     lowSpeedLimit(102400),
00102     port(ftpPort) {
00103     setRemoteUrl(url);
00104 
00105     /* initialise curl */
00106     curl_global_init(CURL_GLOBAL_ALL);
00107 
00108     /* get a curl handle */
00109     this->ehandle = curl_easy_init();
00110 
00111     if (!this->ehandle) {
00112         this->lasterror = CURLE_FAILED_INIT;
00113     } else {
00114         /* set timeout behaviour */
00115         curl_easy_setopt(this->ehandle, CURLOPT_LOW_SPEED_LIMIT,    this->lowSpeedLimit);
00116         curl_easy_setopt(this->ehandle, CURLOPT_LOW_SPEED_TIME,     this->timeout);
00117         if(this->port != 0)
00118             curl_easy_setopt(this->ehandle, CURLOPT_PORT, this->port);
00119     }
00120 }
00121 
00122 
00123 MMSFiletransfer::~MMSFiletransfer() {
00124     curl_easy_cleanup(this->ehandle);
00125     curl_global_cleanup();
00126 }
00127 
00128 
00129 void MMSFiletransfer::setVerboseInformation(bool enable) {
00130     curl_easy_setopt(this->ehandle, CURLOPT_VERBOSE, (enable ? 1L : 0L));
00131 }
00132 
00133 
00134 void MMSFiletransfer::setAuthData(const string user, const string password) {
00135     std::string auth = user;
00136     if (0 != password.length())
00137         auth += ":" + password;
00138 
00139     curl_easy_setopt(this->ehandle, CURLOPT_USERPWD, auth.c_str());
00140 }
00141 
00142 
00143 bool MMSFiletransfer::performUpload(const string localfile, const string remoteName, bool resume) {
00144     FILE *hd_src;
00145     struct stat file_info;
00146 
00147     /* enable uploading */
00148     curl_easy_setopt(this->ehandle, CURLOPT_UPLOAD, 1L);
00149     /* enable curl to create missing dirs on upload */
00150     curl_easy_setopt(this->ehandle, CURLOPT_FTP_CREATE_MISSING_DIRS, 1L);
00151 
00152     /* register progress callback */
00153     curl_easy_setopt(this->ehandle, CURLOPT_NOPROGRESS, 0L);
00154     curl_easy_setopt(this->ehandle, CURLOPT_PROGRESSFUNCTION, progress_callback);
00155     curl_easy_setopt(this->ehandle, CURLOPT_PROGRESSDATA, this);
00156 
00157     if (resume) {
00158         curl_easy_setopt(this->ehandle, CURLOPT_RESUME_FROM, -1L);
00159     }
00160 
00161     /* specify target */
00162     curl_easy_setopt(this->ehandle, CURLOPT_URL, (this->remoteUrl + remoteName).c_str());
00163 
00164     /* get the file size of the local file */
00165     if (stat(localfile.c_str(), &file_info)) {
00166         /* throw error */
00167         this->lasterror = CURLE_FILE_COULDNT_READ_FILE;
00168         return false;
00169     }
00170 
00171     /* get a FILE * of the same file */
00172     hd_src = fopen(localfile.c_str(), "rb");
00173     if(!hd_src) {
00174         this->lasterror = CURLE_FILE_COULDNT_READ_FILE;
00175         return false;
00176     }
00177 
00178     /* now specify which file to upload */
00179     curl_easy_setopt(this->ehandle, CURLOPT_READFUNCTION, read_callback);
00180     curl_easy_setopt(this->ehandle, CURLOPT_READDATA, hd_src);
00181 
00182     curl_easy_setopt(this->ehandle, CURLOPT_INFILESIZE, (long)file_info.st_size);
00183 
00184     /* Now run off and do what you've been told! */
00185     this->lasterror = curl_easy_perform(this->ehandle);
00186     if (this->lasterror != CURLE_OK)
00187         curl_easy_setopt(this->ehandle, CURLOPT_FRESH_CONNECT, 1);
00188     else
00189         curl_easy_setopt(this->ehandle, CURLOPT_FRESH_CONNECT, 0);
00190 
00191     fclose(hd_src); /* close the local file */
00192 
00193     return (this->lasterror == CURLE_OK);
00194 }
00195 
00196 
00197 bool MMSFiletransfer::performDownload(const string localfile, const string remoteName, bool resume) {
00198     struct stat file_info;
00199     FtpFile ftpfile = { localfile.c_str(), /* name to store the file as if succesful */
00200     NULL };
00201 
00202     /* register progress callback */
00203     curl_easy_setopt(this->ehandle, CURLOPT_NOPROGRESS, 0L);
00204     curl_easy_setopt(this->ehandle, CURLOPT_PROGRESSFUNCTION, progress_callback);
00205     curl_easy_setopt(this->ehandle, CURLOPT_PROGRESSDATA, this);
00206 
00207     if (resume) {
00208         if (!stat(localfile.c_str(), &file_info)) {
00209             curl_easy_setopt(this->ehandle, CURLOPT_RESUME_FROM, (long)file_info.st_size);
00210         }
00211     }
00212 
00213     if (!fopen(ftpfile.filename, (resume ? "ab" : "wb"))) {
00214         this->lasterror = CURLE_FILE_COULDNT_READ_FILE;
00215         return false;
00216     }
00217 
00218     curl_easy_setopt(this->ehandle, CURLOPT_URL, (this->remoteUrl + remoteName).c_str());
00219 
00220     /* Set a pointer to our struct to pass to the callback */
00221     curl_easy_setopt(this->ehandle, CURLOPT_WRITEDATA, &ftpfile);
00222 
00223     /* Define our callback to get called when there's data to be written */
00224     curl_easy_setopt(this->ehandle, CURLOPT_WRITEFUNCTION, write_callback);
00225 
00226     this->lasterror = curl_easy_perform(this->ehandle);
00227     if (this->lasterror != CURLE_OK)
00228         curl_easy_setopt(this->ehandle, CURLOPT_FRESH_CONNECT, 1);
00229     else
00230         curl_easy_setopt(this->ehandle, CURLOPT_FRESH_CONNECT, 0);
00231 
00232 
00233     if (ftpfile.stream) {
00234         fclose(ftpfile.stream); /* close the local file */
00235     }
00236 
00237     return (this->lasterror == CURLE_OK);
00238 }
00239 
00240 
00241 bool MMSFiletransfer::deleteRemoteFile(const string remoteFile) {
00242     std::string ftpcommand = "";
00243     struct curl_slist *slist=NULL;
00244 
00245     ftpcommand = "DELE " + remoteFile;
00246     slist = curl_slist_append(slist, "CWD ~");
00247     slist = curl_slist_append(slist, ftpcommand.c_str());
00248     /* pass the list of custom commands to the handle */
00249     curl_easy_setopt(this->ehandle, CURLOPT_QUOTE, slist);
00250 
00251     curl_easy_setopt(this->ehandle, CURLOPT_URL, this->remoteUrl.c_str());
00252     curl_easy_setopt(this->ehandle, CURLOPT_HEADER, 1);
00253 
00254     /* turn off file transfer */
00255     curl_easy_setopt(this->ehandle, CURLOPT_NOBODY, 1);
00256     this->lasterror = curl_easy_perform(this->ehandle);
00257     if (this->lasterror != CURLE_OK)
00258         curl_easy_setopt(this->ehandle, CURLOPT_FRESH_CONNECT, 1);
00259     else
00260         curl_easy_setopt(this->ehandle, CURLOPT_FRESH_CONNECT, 0);
00261 
00262     curl_easy_setopt(this->ehandle, CURLOPT_HEADER, 0);
00263     curl_easy_setopt(this->ehandle, CURLOPT_NOBODY, 0);
00264     curl_slist_free_all(slist);
00265     curl_easy_setopt(this->ehandle, CURLOPT_QUOTE, NULL);
00266 
00267     return (this->lasterror == CURLE_OK);
00268 }
00269 
00270 
00271 bool MMSFiletransfer::getListing(char **buffer, string directory, bool namesOnly) {
00272     this->buffer = NULL;
00273     this->buf_len = 0;
00274     this->buf_pos = 0;
00275 
00276     /* append trailing / if necessary */
00277     if ((directory.length() - 1) != directory.find('/', directory.length() - 1)) {
00278         directory.append("/");
00279     }
00280     curl_easy_setopt(this->ehandle, CURLOPT_URL, (this->remoteUrl + directory).c_str());
00281 
00282     /* Set a pointer to our struct to pass to the callback */
00283     curl_easy_setopt(this->ehandle, CURLOPT_WRITEDATA, this);
00284 
00285     /* Define our callback to get called when there's data to be written */
00286     curl_easy_setopt(this->ehandle, CURLOPT_WRITEFUNCTION, c_mem_write_callback);
00287     curl_easy_setopt(this->ehandle, CURLOPT_DIRLISTONLY, (namesOnly ? 1L : 0L));
00288 
00289     this->lasterror = curl_easy_perform(this->ehandle);
00290 
00291     if (this->lasterror != CURLE_OK)
00292         curl_easy_setopt(this->ehandle, CURLOPT_FRESH_CONNECT, 1);
00293     else
00294         curl_easy_setopt(this->ehandle, CURLOPT_FRESH_CONNECT, 0);
00295 
00296     *buffer = this->buffer;
00297     return (this->lasterror == CURLE_OK);
00298 }
00299 
00300 
00301 void MMSFiletransfer::setRemoteUrl(const string url) {
00302     this->remoteUrl = "ftp://" + url;
00303 
00304     /* append trailing / if necessary */
00305     if ((this->remoteUrl.length() - 1) != this->remoteUrl.find('/', this->remoteUrl.length() - 1)) {
00306         this->remoteUrl.append("/");
00307     }
00308 }
00309 
00310 
00311 const string MMSFiletransfer::getRemoteUrl() {
00312     return this->remoteUrl;
00313 }
00314 
00315 
00316 void MMSFiletransfer::setTimeout(const long timeout) {
00317     this->timeout = timeout;
00318     curl_easy_setopt(this->ehandle, CURLOPT_LOW_SPEED_TIME, timeout);
00319 }
00320 
00321 
00322 const long MMSFiletransfer::getTimeout() {
00323     return this->timeout;
00324 }
00325 
00326 
00327 void MMSFiletransfer::setFtpPort(const unsigned int ftpPort) {
00328     if((this->port != ftpPort) && (0 != ftpPort)) {
00329         this->port = ftpPort;
00330         curl_easy_setopt(this->ehandle, CURLOPT_PORT, this->port);
00331     }
00332 }
00333 
00334 
00335 const unsigned int MMSFiletransfer::getFtpPort() {
00336     return this->port;
00337 }
00338 
00339 
00340 void MMSFiletransfer::setLowSpeedLimit(const long limit) {
00341     this->lowSpeedLimit = limit;
00342     curl_easy_setopt(this->ehandle, CURLOPT_LOW_SPEED_LIMIT, limit);
00343 }
00344 
00345 
00346 const long MMSFiletransfer::getLowSpeedLimit() {
00347     return this->lowSpeedLimit;
00348 }
00349 
00350 
00351 int MMSFiletransfer::getLastError(string *errormsg = NULL) {
00352     if (errormsg) {
00353         *errormsg = (this->lasterror ? curl_easy_strerror(this->lasterror) : NULL);
00354     }
00355     return this->lasterror;
00356 }
00357 
00358 #endif /*__HAVE_CURL__*/

Generated by doxygen