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