00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
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         
00046         out->stream = fopen(out->filename, "ab");
00047         if (!out->stream)
00048             return -1; 
00049     }
00050 
00051     return fwrite(buffer, size, nmemb, out->stream);
00052 }
00053 
00054 
00055 
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;                  
00066     unsigned int    freebuff;                  
00067 
00068     
00069     size *= nitems;
00070 
00071     
00072     freebuff=this->buf_len - this->buf_pos;
00073 
00074     if(size > freebuff) {
00075         
00076         newbuff=(char*)realloc(this->buffer,this->buf_len + (size - freebuff));
00077         if(newbuff==NULL) {
00078             size=freebuff;
00079         }
00080         else {
00081             
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     
00106     curl_global_init(CURL_GLOBAL_ALL);
00107 
00108     
00109     this->ehandle = curl_easy_init();
00110 
00111     if (!this->ehandle) {
00112         this->lasterror = CURLE_FAILED_INIT;
00113     } else {
00114         
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     
00148     curl_easy_setopt(this->ehandle, CURLOPT_UPLOAD, 1L);
00149     
00150     curl_easy_setopt(this->ehandle, CURLOPT_FTP_CREATE_MISSING_DIRS, 1L);
00151 
00152     
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     
00162     curl_easy_setopt(this->ehandle, CURLOPT_URL, (this->remoteUrl + remoteName).c_str());
00163 
00164     
00165     if (stat(localfile.c_str(), &file_info)) {
00166         
00167         this->lasterror = CURLE_FILE_COULDNT_READ_FILE;
00168         return false;
00169     }
00170 
00171     
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     
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     
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); 
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(), 
00200     NULL };
00201 
00202     
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     
00221     curl_easy_setopt(this->ehandle, CURLOPT_WRITEDATA, &ftpfile);
00222 
00223     
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); 
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     
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     
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     
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     
00283     curl_easy_setopt(this->ehandle, CURLOPT_WRITEDATA, this);
00284 
00285     
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     
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