The SWORD Project  1.9.0.svnversion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
curlftpt.cpp
Go to the documentation of this file.
1 /*****************************************************************************
2  *
3  * curlftpt.cpp - CURLFTPTransport
4  *
5  * $Id: curlftpt.cpp 3822 2020-11-03 18:54:47Z scribe $
6  *
7  * Copyright 2004-2013 CrossWire Bible Society (http://www.crosswire.org)
8  * CrossWire Bible Society
9  * P. O. Box 2528
10  * Tempe, AZ 85280-2528
11  *
12  * This program is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU General Public License as published by the
14  * Free Software Foundation version 2.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * General Public License for more details.
20  *
21  */
22 
23 #include <curlftpt.h>
24 
25 #include <filemgr.h>
26 
27 #include <curl/curl.h>
28 #include <curl/easy.h>
29 
30 #include <swlog.h>
31 
32 
34 
35 namespace {
36 
37  struct FtpFile {
38  const char *filename;
39  int fd;
41  };
42 
43 
44  // initialize/cleanup SYSTEMWIDE library with life of this static.
45  static class CURLFTPTransport_init {
46  public:
48  curl_global_init(CURL_GLOBAL_DEFAULT); // curl_easy_init automatically calls it if needed
49  }
50 
52  curl_global_cleanup();
53  }
55 
56 
57  static int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream) {
58  struct FtpFile *out = (struct FtpFile *)stream;
59  if (out && !out->fd && !out->destBuf) {
60  /* open file for writing */
62  if (out->fd < 0)
63  return -1; /* failure, can't open file to write */
64  }
65  if (out->destBuf) {
66  int s = (int)out->destBuf->size();
67  out->destBuf->size(s+(size*nmemb));
68  memcpy(out->destBuf->getRawData()+s, buffer, size*nmemb);
69  return (int)nmemb;
70  }
71  return (int)FileMgr::write(out->fd, buffer, size * nmemb);
72  }
73 
74 
75  struct MyProgressData {
77  bool *term;
78  };
79 
80 
81  static int my_fprogress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) {
82  if (clientp) {
83  MyProgressData *pd = (MyProgressData *)clientp;
84 SWLOGD("CURLFTPTransport report progress: totalSize: %ld; xfered: %ld\n", (long)dltotal, (long)dlnow);
85  if (pd->sr) {
86  if (dltotal < 0) dltotal = 0;
87  if (dlnow < 0) dlnow = 0;
88  if (dlnow > dltotal) dlnow = dltotal;
89  pd->sr->update(dltotal, dlnow);
90  }
91  if (*(pd->term)) return 1;
92  }
93  return 0;
94  }
95 
96 
97  static int my_trace(CURL *handle, curl_infotype type, unsigned char *data, size_t size, void *userp) {
98  SWBuf header;
99  (void)userp; /* prevent compiler warning */
100  (void)handle; /* prevent compiler warning */
101 
102  switch (type) {
103  case CURLINFO_TEXT: header = "TEXT"; break;
104  case CURLINFO_HEADER_OUT: header = "=> Send header"; break;
105  case CURLINFO_HEADER_IN: header = "<= Recv header"; break;
106 
107  // these we don't want to log (HUGE)
108  case CURLINFO_DATA_OUT: header = "=> Send data";
109  case CURLINFO_SSL_DATA_OUT: header = "=> Send SSL data";
110  case CURLINFO_DATA_IN: header = "<= Recv data";
111  case CURLINFO_SSL_DATA_IN: header = "<= Recv SSL data";
112  default: /* in case a new one is introduced to shock us */
113  return 0;
114  }
115 
116  if (size > 120) size = 120;
117  SWBuf text;
118  text.size(size);
119  memcpy(text.getRawData(), data, size);
120 SWLOGD("CURLFTPTransport: %s: %s", header.c_str(), text.c_str());
121  return 0;
122  }
123 }
124 
125 
127  session = (CURL *)curl_easy_init();
128 }
129 
130 
132  curl_easy_cleanup(session);
133 }
134 
135 
136 char CURLFTPTransport::getURL(const char *destPath, const char *sourceURL, SWBuf *destBuf) {
137  signed char retVal = 0;
138  struct FtpFile ftpfile = {destPath, 0, destBuf};
139 
140  CURLcode res;
141 
142  if (session) {
143 
144  struct MyProgressData pd;
145  pd.sr = statusReporter;
146  pd.term = &term;
147 
148  curl_easy_setopt(session, CURLOPT_URL, sourceURL);
149 
150  SWBuf credentials = u + ":" + p;
151  curl_easy_setopt(session, CURLOPT_USERPWD, credentials.c_str());
152  curl_easy_setopt(session, CURLOPT_WRITEFUNCTION, my_fwrite);
153  if (!passive)
154  curl_easy_setopt(session, CURLOPT_FTPPORT, "-");
155  curl_easy_setopt(session, CURLOPT_NOPROGRESS, 0);
156  curl_easy_setopt(session, CURLOPT_PROGRESSDATA, &pd);
157  curl_easy_setopt(session, CURLOPT_PROGRESSFUNCTION, my_fprogress);
158 
159 
160  curl_easy_setopt(session, CURLOPT_DEBUGFUNCTION, my_trace);
161  /* Set a pointer to our struct to pass to the callback */
162  curl_easy_setopt(session, CURLOPT_FILE, &ftpfile);
163 
164  /* Switch on full protocol/debug output */
165  curl_easy_setopt(session, CURLOPT_VERBOSE, true);
166 #ifndef OLDCURL
167  curl_easy_setopt(session, CURLOPT_CONNECTTIMEOUT_MS, timeoutMillis);
168  curl_easy_setopt(session, CURLOPT_TIMEOUT_MS, timeoutMillis);
169 #else
170  curl_easy_setopt(session, CURLOPT_CONNECTTIMEOUT, timeoutMillis/1000);
171  curl_easy_setopt(session, CURLOPT_TIMEOUT, timeoutMillis/1000);
172 #endif
173  /* FTP connection settings */
174 
175 #if (LIBCURL_VERSION_MAJOR > 7) || \
176  ((LIBCURL_VERSION_MAJOR == 7) && (LIBCURL_VERSION_MINOR > 10)) || \
177  ((LIBCURL_VERSION_MAJOR == 7) && (LIBCURL_VERSION_MINOR == 10) && (LIBCURL_VERSION_PATCH >= 5))
178 # define EPRT_AVAILABLE 1
179 #endif
180 
181 #ifdef EPRT_AVAILABLE
182  curl_easy_setopt(session, CURLOPT_FTP_USE_EPRT, 0);
183 SWLOGD("***** using CURLOPT_FTP_USE_EPRT\n");
184 #endif
185 
186 
187 SWLOGD("***** About to perform curl easy action. \n");
188 SWLOGD("***** destPath: %s \n", destPath);
189 SWLOGD("***** sourceURL: %s \n", sourceURL);
190  res = curl_easy_perform(session);
191 SWLOGD("***** Finished performing curl easy action. \n");
192 
193  // it seems CURL tries to use this option data later for some reason, so we unset here
194  curl_easy_setopt(session, CURLOPT_PROGRESSDATA, (void*)NULL);
195 
196  if (CURLE_OK != res) {
197  if (CURLE_OPERATION_TIMEDOUT == res
198 // older CURL doesn't define this
199 #ifdef CURLE_FTP_ACCEPT_TIMEOUT
200  || CURLE_FTP_ACCEPT_TIMEOUT == res
201 #endif
202  ) {
203  retVal = -2;
204  }
205  else {
206  retVal = -1;
207  }
208  }
209  }
210 
211  if (ftpfile.fd > 0)
212  FileMgr::closeFile(ftpfile.fd); /* close the local file */
213 
214  return retVal;
215 }
216 
217 
219 
#define SWORD_NAMESPACE_START
Definition: defs.h:39
virtual char getURL(const char *destPath, const char *sourceURL, SWBuf *destBuf=0)
Definition: curlftpt.cpp:136
Definition: swbuf.h:47
static int my_trace(CURL *handle, curl_infotype type, unsigned char *data, size_t size, void *userp)
Definition: curlftpt.cpp:97
preg buffer
Definition: regex.c:8089
static void closeFile(int fd)
Definition: filemgr.cpp:491
static int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
Definition: curlftpt.cpp:57
CURLFTPTransport(const char *host, StatusReporter *statusReporter=0)
Definition: curlftpt.cpp:126
static int my_fprogress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
Definition: curlftpt.cpp:81
return NULL
Definition: regex.c:7953
char * getRawData()
Definition: swbuf.h:379
const char * c_str() const
Definition: swbuf.h:158
unsigned long size() const
Definition: swbuf.h:185
virtual void update(unsigned long totalBytes, unsigned long completedBytes)
static long write(int fd, const void *buf, long count)
Definition: filemgr.cpp:115
int size
Definition: regex.c:5043
static int createPathAndFile(const char *fName)
Definition: filemgr.cpp:479
static class SWORD_NAMESPACE_START::CURLFTPTransport_init _curlFTPTransport_init
#define SWORD_NAMESPACE_END
Definition: defs.h:40
#define SWLOGD(...)
Definition: defs.h:187
StatusReporter * statusReporter
Definition: remotetrans.h:59
CURL * session
Definition: curlftpt.h:35