Hello, I'm reviving this "old" thread because I've been working on this code and I want to submit a patch to arne, so I present my code here for peer review (sorry it's quite large).
Changes on MainFrm.cpp
Code: Select all
string decodeURL(const string& s) {
string sbuf;
static const string validHexChars ="0123456789ABCDEF";
string hexString;
string::size_type x = 0;
int l = s.length() ;
int ch = -1 ;
int b, sumb = 0;
int hb, lb;
for (int i = 0, more = -1 ; i < l ; i++) {
/* Get next byte b from URL segment s */
switch (ch = s.at(i)) {
case '%':
hexString = s.substr(i + 1, 2);
if ( (x = hexString.find_first_not_of(validHexChars, 0)) == string ::npos) {
ch = s.at (++i) ;
hb = (isdigit((char) ch)
? ch - '0'
: 10+tolower((char) ch) - 'a') & 0xF;
ch = s.at (++i) ;
lb = (isdigit ((char) ch)
? ch - '0'
: 10+tolower((char) ch)-'a') & 0xF ;
b = (hb << 4) | lb ;
}
else {
b = ch;
}
break;
//case '+':
// b = ' ' ;
// break ;
default:
b = ch;
}
/* Decode byte b as UTF-8, sumb collects incomplete chars */
if ((b & 0xc0) == 0x80) { // 10xxxxxx (continuation byte)
sumb = (sumb << 6) | (b & 0x3f) ; // Add 6 bits to sumb
if (--more == 0) sbuf += ((char) sumb) ; // Add char to sbuf
} else if ((b & 0x80) == 0x00) { // 0xxxxxxx (yields 7 bits)
sbuf += ((char) b) ; // Store in sbuf
} else if ((b & 0xe0) == 0xc0) { // 110xxxxx (yields 5 bits)
sumb = b & 0x1f;
more = 1; // Expect 1 more byte
} else if ((b & 0xf0) == 0xe0) { // 1110xxxx (yields 4 bits)
sumb = b & 0x0f;
more = 2; // Expect 2 more bytes
} else if ((b & 0xf8) == 0xf0) { // 11110xxx (yields 3 bits)
sumb = b & 0x07;
more = 3; // Expect 3 more bytes
} else if ((b & 0xfc) == 0xf8) { // 111110xx (yields 2 bits)
sumb = b & 0x03;
more = 4; // Expect 4 more bytes
} else /*if ((b & 0xfe) == 0xfc)*/ { // 1111110x (yields 1 bit)
sumb = b & 0x01;
more = 5; // Expect 5 more bytes
}
/* We don't test if the UTF-8 encoding is well-formed */
}
return sbuf ;
}
void MainFrame::parseCommandLine(const string& cmdLine) {
string::size_type i = 0;
string::size_type j = 0;
string::size_type k = 0;
string::size_type l = 0;
string::size_type m = 0;
string::size_type x = 0;
// string tmpCmdLine = decodeURL(cmdLine);
if ( (j = cmdLine.find("dchub://", i)) != string::npos) {
i = j + 8;
string server;
string user;
string path = Util::emptyString;
string filename = Util::emptyString;
string filesize = Util::emptyString;
if( (j = cmdLine.find('/', i)) == string::npos) {
server = cmdLine.substr(i);
}
else {
server = cmdLine.substr(i, j-i);
i = j + 1;
// Changed for compatibility
// if( (j = cmdLine.find_first_of("\\/ ", i)) == string::npos) {
if( (j = cmdLine.find_first_of("$ ", i)) == string::npos) {
user = cmdLine.substr(i);
}
else {
user = cmdLine.substr(i, j-i);
j++;
if( (k = cmdLine.find_last_of("\\/")) != string::npos) {
if(k > j) {
path = cmdLine.substr(j, k-j);
k++;
if( (x = path.find("/")) != string::npos) {
while (x != string::npos) {
path.replace(x, 1, "\\");
x = path.find("/");
}
}
if ( (path.at(path.length() - 1)) != '\\') {
path += "\\";
}
if( (l = cmdLine.rfind("?")) != string::npos) {
filename = cmdLine.substr(k, l-k);
if(( (m = cmdLine.rfind("&")) != string::npos) && (m > l)) {
filesize = cmdLine.substr(l, m-l);
l++;
}
else {
filesize = cmdLine.substr(l+1);
}
if(filesize.find("size=") != string::npos) {
filesize = filesize.substr(5);
}
}
else {
path = cmdLine.substr(j) ;
if( (x = path.find("/")) != string::npos) {
while (x != string::npos) {
path.replace(x, 1, "\\");
x = path.find("/");
}
}
if ( (path.at(path.length() -1)) != '\\') {
path += "\\";
}
}
}
}
}
if(!server.empty()) {
HubFrame::openWindow(m_hWndMDIClient, &ctrlTab, server);
}
if(!user.empty()) {
User::Ptr up = ClientManager::getInstance()->getUser(user);
if(path.empty()) {
try {
QueueManager::getInstance()->addList(up);
} catch (...) {
// ...
}
}
else {
string tempTarget = Util::emptyString;
path = decodeURL(path);
filename = decodeURL(filename);
if(!filename.empty()) {
string fullFilePath = path + filename;
tempTarget = SETTING(DOWNLOAD_DIRECTORY) + filename;
try {
QueueManager::getInstance()->add(fullFilePath, filesize, up, tempTarget);
} catch(Exception e) {
ctrlStatus.SetText(0, e.getError().c_str());
}
}
else {
tempTarget = SETTING(DOWNLOAD_DIRECTORY);
try {
QueueManager::getInstance()->addDirectory(path, up, tempTarget);
} catch(Exception e) {
ctrlStatus.SetText(0, e.getError().c_str());
}
}
}
}
}
}
}
As you can see on the line I commented out that says "Changed for compatbility" the dchub:// URL now should look like this:
dchub://hub.address.net:1234/Username$/ ... ?size=1234
We need to delimit username and path with a '$' because slashes '/' are allowed as part of the username.
You also might be wondering what the decodeURL function is doing there. Well, I had to put it there because of browser incompatibilities. Opera, Mozilla and probably other browsers encode URLs when they contain extended characters. For example, a file called "Olé" will be passed to DC++ by Opera as "Ol%C3%A9" which is the URL encoded UTF-8 equivalent. The easiest way I found to work around this is to make DC++ decode all url encoded chars. This function was ported over from the one provided by w3.org.
Anyway, I think that pretty much covers it. Any comments/feedback will be greatly appreciated.