1 /*****************************************************************************
2 *
3 * remotetrans.cpp -
4 *
5 * $Id: remotetrans.cpp 3515 2017-11-01 11:38:09Z 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 <remotetrans.h>
24 #include <filemgr.h>
25
26 #include <fcntl.h>
27 #include <dirent.h>
28 #include <swlog.h>
29
30
31 extern "C" {
32 #include <ftpparse.h>
33 }
34
35
36 using std::vector;
37
38
39 SWORD_NAMESPACE_START
40
41
42 namespace {
43
removeTrailingSlash(SWBuf & buf)44 void removeTrailingSlash(SWBuf &buf) {
45 int len = buf.size();
46 if ((buf[len-1] == '/')
47 || (buf[len-1] == '\\'))
48 buf.size(len-1);
49 }
50
51 };
52
53
preStatus(long totalBytes,long completedBytes,const char * message)54 void StatusReporter::preStatus(long totalBytes, long completedBytes, const char *message) {
55 }
56
57
statusUpdate(double dtTotal,double dlNow)58 void StatusReporter::statusUpdate(double dtTotal, double dlNow) {
59 }
60
61
RemoteTransport(const char * host,StatusReporter * statusReporter)62 RemoteTransport::RemoteTransport(const char *host, StatusReporter *statusReporter) {
63 this->statusReporter = statusReporter;
64 this->host = host;
65 u = "ftp";
66 p = "installmgr@user.com";
67 term = false;
68 passive = true;
69 unverifiedPeerAllowed = true;
70 }
71
72
~RemoteTransport()73 RemoteTransport::~RemoteTransport() {
74 }
75
76
77 // override this method in your real transport class
getURL(const char * destPath,const char * sourceURL,SWBuf * destBuf)78 char RemoteTransport::getURL(const char *destPath, const char *sourceURL, SWBuf *destBuf) {
79 SWLog::getSystemLog()->logWarning("RemoteTransport::getURL called but unsupported");
80 char retVal = -1;
81 return retVal;
82 }
83
84 // override this method in your real transport class
putURL(const char * destURL,const char * sourcePath,SWBuf * sourceBuf)85 char RemoteTransport::putURL(const char *destURL, const char *sourcePath, SWBuf *sourceBuf) {
86 SWLog::getSystemLog()->logWarning("RemoteTransport::putURL called but unsupported");
87 char retVal = -1;
88 return retVal;
89 }
90
91
getDirList(const char * dirURL)92 vector<struct DirEntry> RemoteTransport::getDirList(const char *dirURL) {
93
94 SWLog::getSystemLog()->logDebug("RemoteTransport::getDirList(%s)", dirURL);
95 vector<struct DirEntry> dirList;
96
97 SWBuf dirBuf;
98 if (!getURL("", dirURL, &dirBuf)) {
99 char *start = dirBuf.getRawData();
100 char *end = start;
101 while (start < (dirBuf.getRawData()+dirBuf.size())) {
102 struct ftpparse item;
103 bool looking = true;
104 for (end = start; *end; end++) {
105 if (looking) {
106 if ((*end == 10) || (*end == 13)) {
107 *end = 0;
108 looking = false;
109 }
110 }
111 else if ((*end != 10) && (*end != 13))
112 break;
113 }
114 SWLog::getSystemLog()->logDebug("getDirList: parsing item %s(%d)\n", start, end-start);
115 int status = ftpparse(&item, start, (int)(end - start));
116 // in ftpparse.h, there is a warning that name is not necessarily null terminated
117 SWBuf name;
118 name.append(item.name, item.namelen);
119 SWLog::getSystemLog()->logDebug("getDirList: got item %s\n", name.c_str());
120 if (status && name != "." && name != "..") {
121 struct DirEntry i;
122 i.name = name;
123 i.size = item.size;
124 i.isDirectory = (item.flagtrycwd == 1);
125 dirList.push_back(i);
126 }
127 start = end;
128 }
129 }
130 else {
131 SWLog::getSystemLog()->logWarning("getDirList: failed to get dir %s\n", dirURL);
132 }
133 return dirList;
134 }
135
136
copyDirectory(const char * urlPrefix,const char * dir,const char * dest,const char * suffix)137 int RemoteTransport::copyDirectory(const char *urlPrefix, const char *dir, const char *dest, const char *suffix) {
138 SWLog::getSystemLog()->logDebug("RemoteTransport::copyDirectory");
139 int retVal = 0;
140
141 SWBuf url = SWBuf(urlPrefix) + SWBuf(dir);
142 removeTrailingSlash(url);
143 url += '/';
144
145 SWLog::getSystemLog()->logDebug("NetTransport: getting dir %s\n", url.c_str());
146 vector<struct DirEntry> dirList = getDirList(url.c_str());
147
148 if (!dirList.size()) {
149 SWLog::getSystemLog()->logWarning("NetTransport: failed to read dir %s\n", url.c_str());
150 return -1;
151 }
152
153 // append files in sub directories and calculate total download size
154 unsigned int i = 0;
155 long totalBytes = 0;
156 for (;;) {
157 if (i == dirList.size())
158 break;
159
160 struct DirEntry &e = dirList.at(i);
161
162 if (e.isDirectory) {
163 SWBuf name(e.name); // &e will be invalidated after first insertion
164 vector<struct DirEntry> sd = getDirList((url + name + '/').c_str());
165 for (unsigned int ii = 0; ii < sd.size(); ii++) {
166 sd[ii].name = name + '/' + sd[ii].name;
167 dirList.push_back(sd[ii]);
168 }
169 dirList.erase(dirList.begin() + i);
170 }
171 else {
172 totalBytes += e.size;
173 i++;
174 }
175 }
176
177 long completedBytes = 0;
178 for (i = 0; i < dirList.size(); i++) {
179 struct DirEntry &dirEntry = dirList[i];
180 SWBuf buffer = (SWBuf)dest;
181 removeTrailingSlash(buffer);
182 buffer += "/";
183 buffer += dirEntry.name;
184 if (!strcmp(&buffer.c_str()[buffer.length()-strlen(suffix)], suffix)) {
185 SWBuf buffer2 = "Downloading (";
186 buffer2.appendFormatted("%d", i+1);
187 buffer2 += " of ";
188 buffer2.appendFormatted("%d", dirList.size());
189 buffer2 += "): ";
190 buffer2 += dirEntry.name;
191 if (statusReporter)
192 statusReporter->preStatus(totalBytes, completedBytes, buffer2.c_str());
193 FileMgr::createParent(buffer.c_str()); // make sure parent directory exists
194 SWTRY {
195 SWBuf url = (SWBuf)urlPrefix + (SWBuf)dir;
196 removeTrailingSlash(url);
197 url += "/";
198 url += dirEntry.name;
199 if (getURL(buffer.c_str(), url.c_str())) {
200 SWLog::getSystemLog()->logWarning("copyDirectory: failed to get file %s\n", url.c_str());
201 return -2;
202 }
203 completedBytes += dirEntry.size;
204 }
205 SWCATCH (...) {}
206 if (term) {
207 retVal = -3;
208 break;
209 }
210 }
211 }
212 return retVal;
213 }
214
215
216 #if defined(__GNUC__)
217 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
218 #endif
update(unsigned long totalBytes,unsigned long completedBytes)219 void StatusReporter::update(unsigned long totalBytes, unsigned long completedBytes) {
220 statusUpdate(totalBytes, completedBytes);
221 }
222
223
224 SWORD_NAMESPACE_END
225
226